OOP and Classes
This tutorial moves very fast. If you would like a slower, more in-depth intro to Python, we suggest you take our Intro to Python Evening Course. It's the perfect way to become familiar with Python + gain experience using Python to solve challenging problems.
This web tutorial follows the Jupyter notebook found on GitHub. If you are viewing it using GitHub, then you cannot execute the cells that contain Python code. To view and run this notebook you'll need to install Jupyter on your computer before you continue. See these installation instructionsfor help!
From wikipedia: "Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods."
Object-oriented programming has many benefits (see encapsulation, polymorphism, and inheritance in the wiki), but it also kind of matches how we think about the world. The world is composed of objects, where objects can be people, houses, cars, buildings, etc. These objects have some properties about them (i.e. they contain data), and they can do things (i.e. they have methods that can be applied). Object oriented programming approaches a programming problem by using objects that interact with each other, much like they do in the real world.
1.) Class - used to refer to the abstract concept of an object.
2.) Object - An actual instance of a class.
3.) Instance - What Python returns when you tell it to create a class.
4.) self - Inside of a class, a variable for the instance/object being accessed (i.e. it holds a reference to the instance/object of that class).
5.) attribute / field / property - A property or piece of data that a class has, stored in a variable. All attributes/fields/properties within a class are assigned via self.
6.) method / procedure - A block of code that is accessible via the class, and typically acts on or with the classes attributes/fields/properties. All methods/procedures within a class are created via def. (they are really just functions).
From here on out, I will treat attribute, field, and property as interchangeable, and I'll do the same with method and procedure.
Defining a Class
Much like defining a function, there is a common format to defining a class. It is almost exactly the same as defining a function, but we replace
class. That is, we write
class, then the name of the class that we are defining, followed by a set of parentheses, and finally a colon. After the colon is an indented block of code that we use to define the class attributes and methods. One subtle difference is that with functions, the standard is to name these beginning in lowercase and seperating words with underscores (snake_case), while with classes, the standard is to name these beginning in uppercase, and not separate words at all (CamelCase).
class MyClass(): # Attributes and methods go in here.
Instantiation is just a fancy word for saying that we're going to create an instance of a particular class.
my_class = MyClass() # Now we have my_class as an instance of MyClass
Inside of a class, we can have both attributes and methods. We can then think of these attributes and methods as belonging to the class, and they become accessible via any instances of the class (through dot notation, which we'll get to in a second). Inside of the class, all of these attributes and methods are set and retrieved via self. Let's dive in...
The _init_() method
Almost every class you ever write will have an _init_() method. This method gets called every time that you create a new instance of a class, and handles any kind of setup that the class may require. Setup typically just involves assigning values to variables, which we can do with or without passing values in.
class MyClass(): def __init__(self): # No values have been passed in here. self.meetup_name = 'Data Science' my_class = MyClass() print my_class.meetup_name # Note the dot notation here to access the 'meetup_name' field.
class MyClass(): def __init__(self, meetup_name): # Here we passed the value that will be assigned in. Note the assignment using self. self.meetup_name = meetup_name my_class = MyClass('Data Science') print my_class.meetup_name
What happens if we don't use self?
class MyClass(): def __init__(self, meetup_name): # Here we passed the value that will be assigned in. meetup_name = meetup_name my_class = MyClass('Data Science') print my_class.meetup_name
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-3-ee58f148da2d> in <module>() 6 7 my_class = MyClass('Data Science') ----> 8 print my_class.meetup_name AttributeError: MyClass instance has no attribute 'meetup_name'
The _init_() method is a special type of magic method. Magic methods allow you to build a lot of functionality into your classes, most of which allow you to interact with your classes using a lot of the built-in functions. I don't use these often in my day to day, but the _len_(), __str\(), __repr() ones are pretty common. The first lets you use the len() function on instances of your class, and the second to allow you to define a readable display of an instance of your class (used when printing or applying the str() function).
We can of course define other methods of our classes...
class MyClass(): def __init__(self, meetup_name='Data Science'): # Here we passed the value that will be assigned in. self.meetup_name = meetup_name self.meetup_questions =  self.meetup_answers =  def add_question(self, question): # Note the referal to the meetup_questions field via self. self.meetup_questions.append(question) def add_answer(self, answer): self.meetup_answers.append(answer) my_class = MyClass() print my_class.meetup_name print my_class.meetup_questions print my_class.meetup_answers
Data Science  
my_class.add_question('What question should I ask?') my_class.add_answer('Think of anything!')
print my_class.meetup_name print my_class.meetup_questions print my_class.meetup_answers
Data Science ['What question should I ask?'] ['Think of anything!']
Using Multiple Objects
That's the whole point of them, right?
class Member(): def __init__(self, name): self.name = name self.questions_asked =  self.question_answers =  def add_question(self, question): self.questions_asked.append(question) def add_answer(self, question): self.question_answers.append(question) class MyClass(): def __init__(self, name='Data Science'): self.name = name self.members =  def num_questions_asked(self): total_questions = 0 for member in members: total_questions += len(member.questions_asked) return total_questions def num_questions_answered(self): total_questions = 0 for member in members: total_questions += len(member.question_answers) return total_questions
# Create some members. josh = Member('Josh') joanna = Member('Joanna') sean = Member('Sean') members = [josh, joanna, sean] # Create a class and add the members to it. my_class = MyClass() my_class.members = members print my_class.name for member in my_class.members: print member.name
Data Science Josh Joanna Sean
josh.add_question('Hellooooo?') joanna.add_answer('???????') print my_class.num_questions_asked() print my_class.num_questions_answered()