OOP2
OOP2
Python Tricks
Email…
◦ Class Attributes
• Instantiating Objects
◦ What’s Going On?
◦ Review Exercises (#1)
• Instance Methods
◦ Modifying Attributes
• Python Object Inheritance
◦ Dog Park Example
◦ Extending the Functionality of a Parent Class
◦ Parent vs. Child Classes
◦ Overriding the Functionality of a Parent Class
◦ Review Exercises (#2)
• Conclusion
Table of Contents
• What Is Object-Oriented
Programming (OOP)?
• Classes in Python
• Python Objects (Instances)
Watch Now This tutorial has a related video course created by the Real Python
• How To Define a Class in
team. Watch it together with the written tutorial to deepen your understanding:
Python
Intro to Object-Oriented Programming (OOP) in Python
• Instantiating Objects
• Instance Methods
In this article you’ll pick up the following basic concepts of OOP in Python:
• Python Object Inheritance
• Python Classes • Conclusion
• Object Instances
• Defining and Working with Methods
• OOP Inheritance Improve Your Python
Recommended Video Course
Free Bonus: Click here to get access to a free Python OOP Cheat Sheet that
Intro to Object-Oriented
points you to the best tutorials, videos, and books to learn more about Object-
Programming (OOP) in Python
Oriented Programming with Python.
For instance, an object could represent a person with a name property, age, address,
etc., with behaviors like walking, talking, breathing, and running. Or an email with
properties like recipient list, subject, body, etc., and behaviors like adding
attachments and sending.
The key takeaway is that objects are at the center of the object-oriented
programming paradigm, not only representing the data, as in procedural
programming, but in the overall structure of the program as well.
Classes in Python
Focusing first on the data, each thing or object is an instance of some class.
The primitive data structures available in Python, like numbers, strings, and lists are
designed to represent simple things like the cost of something, the name of a poem,
and your favorite colors, respectively.
For example, let’s say you wanted to track a number of different animals. If you used
a list, the first element could be the animal’s name while the second element could
represent its age.
How would you know which element is supposed to be which? What if you had 100
different animals? Are you certain each animal has both a name and an age, and so
forth? What if you wanted to add other properties to these animals? This lacks
organization, and it’s the exact need for classes.
Classes are used to create new user-defined data structures that contain arbitrary
information about something. In the case of an animal, we could create an Animal()
class to track properties about the Animal like the name and age.
Improve Your Python
It’s important to note that a class just provides structure—it’s a blueprint for how
something should be defined, but it doesn’t actually provide any real content itself.
The Animal() class may specify that the name and age are necessary for defining an
animal, but it will not actually state what a specific animal’s name or age is.
It may help to think of a class as an idea for how something should be defined.
Put another way, a class is like a form or questionnaire. It defines the needed
information. After you fill out the form, your specific copy is an instance of the class;
it contains actual information relevant to you.
You can fill out multiple copies to create many different instances, but without the
form as a guide, you would be lost, not knowing what information is required. Thus,
before you can create individual instances of an object, we must first specify what is
needed by defining a class.
Python
class Dog:
pass
You start with the class keyword to indicate that you are creating a class, then you
add the name of the class (using CamelCase notation, starting with a capital letter.)
Also, we used the Python keyword pass here. This is very often used as a place holder
where code will eventually go. It allows us to run this code without throwing an
error.
Note: The above code is correct on Python 3. On Python 2.x (“legacy Python”)
you’d use a slightly different class definition:
Python
The (object) part in parentheses specifies the parent class that you are
inheriting from (more on this below.) In Python 3 this is no longer necessary
because it is the implicit default.
Python
class Dog:
In the case of our Dog() class, each dog has a specific name and age, which is
obviously important to know for when you start actually creating different dogs.
Remember: the class is just for defining the Dog, not actually creating instances of
individual dogs with specific names and ages; we’ll get to that shortly.
Similarly, the self variable is also an instance of the class. Since instances of a class
have varying values we could state Dog.name = name rather than self.name = name.
But since not all dogs share the same name, we need to be able to assign different
values to different instances. Hence the need for the special self variable, which will
help to keep track of individual instances of each class.
NOTE: You will never have to call the __init__() method; it gets called
automatically when you create a new ‘Dog’ instance.
Class Attributes
While instance attributes are specific to each object, class attributes are the same for
all instances—which in this case is all dogs.
Python
class Dog:
# Class Attribute
species = 'mammal'
So while each dog has a unique name and age, every dog will be a mammal.
Instantiating Objects
Instantiating is a fancy term for creating a new, unique instance of a class.
For example:
We started by defining a new Dog() class, then created two new dogs, each assigned
to different objects. So, to create an instance of a class, you use the the class name,
followed by parentheses. Then to demonstrate that each instance is actually
different, we instantiated two more dogs, assigning each to a variable, then tested if
those variables are equal.
Python >>>
Python
class Dog:
# Class Attribute
species = 'mammal'
# Is Philo a mammal?
if philo.species == "mammal":
print("{0} is a {1}!".format(philo.name, philo.species))
NOTE: Notice how we use dot notation to access attributes from each object.
Save this as dog_class.py, then run the program. You should see:
These attributes are passed to the __init__ method, which gets called any time you
create a new instance, attaching the name and age to the object. You might be
wondering why we didn’t have to pass in the self argument.
This is Python magic; when you create a new instance of the class, Python
automatically determines what self is (a Dog in this case) and passes it to the
__init__ method.
Using the same Dog class, instantiate three new dogs, each with a different age.
Then write a function called, get_biggest_number(), that takes any number of
ages (*args) and returns the oldest one. Then output the age of the oldest dog
like so:
Python
# Class Attribute
species = 'mammal'
# Output
print("The oldest dog is {} years old.".format(
get_biggest_number(jake.age, doug.age, william.age)))
Instance Methods
Instance methods are defined inside a class and are used to get the contents of an
instance. They can also be used to perform operations with the attributes of our
objects. Like the __init__ method, the first argument is always self:
Python
class Dog:
# Class Attribute
species = 'mammal'
# instance method
def description(self):
return "{} is {} years old".format(self.name, self.age)
# instance method
def speak(self, sound):
return "{} says {}".format(self.name, sound)
In the latter method, speak(), we are defining behavior. What other behaviors could
you assign to a dog? Look back to the beginning paragraph to see some example
behaviors for other objects.
Modifying Attributes
You can change the value of attributes based on some behavior:
Python >>>
Here, we added a method to send an email, which updates the is_sent variable to
True.
It’s important to note that child classes override or extend the functionality (e.g.,
attributes and behaviors) of parent classes. In other words, child classes inherit all of
the parent’s attributes and behaviors but can also specify different behavior to
follow. The most basic type of class is an object, which generally all other classes
inherit as their parent.
When you define a new class, Python 3 it implicitly uses object as the parent class.
So the following two definitions are equivalent:
Python
class Dog(object):
pass
class Dog:
pass
What’s another way to differentiate one dog from another? How about the dog’s
breed:
Python >>>
Each breed of dog has slightly different behaviors. To take these into account, let’s
create separate classes for each breed. These are child classes of the parent Dog
class.
Python
# Class attribute
species = 'mammal'
# instance method
def description(self):
return "{} is {} years old".format(self.name, self.age)
# instance method
def speak(self, sound):
return "{} says {}".format(self.name, sound)
Read the comments aloud as you work through this program to help you understand
what’s happening, then before you run the program, see if you can predict the
expected output.
# Class attribute
species = 'mammal'
# instance method
def description(self):
return "{} is {} years old".format(self.name, self.age)
# instance method
def speak(self, sound):
return "{} says {}".format(self.name, sound)
Output:
Python
Make sense? Both jim and julie are instances of the Dog() class, while johnnywalker
is not an instance of the Bulldog() class. Then as a sanity check, we tested if julie is
an instance of jim, which is impossible since jim is an instance of a class rather than
a class itself—hence the reason for the TypeError.
Python >>>
The SomeBreed() class inherits the species from the parent class, while the
SomeOtherBreed() class overrides the species, setting it to reptile.
Create a Pets class that holds instances of dogs; this class is completely
separate from the Dog class. In other words, the Dog class does not inherit from
the Pets class. Then assign three dog instances to an instance of the Pets class.
Start with the following code below. Save the file as pets_class.py. Your output
should look like this:
I have 3 dogs.
Tom is 6.
Fletcher is 7.
Larry is 9.
And they're all mammals, of course.
Python
# Parent class
class Dog:
# Class attribute
species = 'mammal'
# instance method
def description(self):
return "{} is {} years old".format(self.name, self.age)
# instance method
def speak(self, sound):
return "{} says {}".format(self.name, sound)
Python
>>>
dogs = []
# Parent class
class Dog:
# Class attribute
species = 'mammal'
# Instance method
def description(self):
return self.name, self.age
# Instance method
def speak(self, sound):
return "%s says %s" % (self.name, sound)
# Instance method
def eat(self):
self.is_hungry = False
# Output
print("I have {} dogs.".format(len(my_pets.dogs)))
for dog in my_pets.dogs:
print("{} is {}.".format(dog.name, dog.age))
I have 3 dogs.
Tom is 6.
Fletcher is 7.
Larry is 9.
And they're all mammals, of course.
My dogs are not hungry.
Python
dogs = []
# Parent class
class Dog:
# Class attribute
species = 'mammal'
# Instance method
def description(self):
return self.name, self.age
# Instance method
def speak(self, sound):
return "%s says %s" % (self.name, sound)
# Instance method
def eat(self):
self.is_hungry = False
# Output
print("I have {} dogs.".format(len(my_pets.dogs)))
for dog in my_pets.dogs:
dog.eat()
print("{} is {}.".format(dog.name, dog.age))
are_my_dogs_hungry = False
for dog in my_pets.dogs:
if dog.is_hungry:
are_my_dogs_hungry = True
Improve Your Python
print("My dogs are hungry.")
else:
print("My dogs are not hungry.")
Next, add a walk() method to both the Pets and Dog classes so that when you
call the method on the Pets class, each dog instance assigned to the Pets class
will walk(). Save this as dog_walking.py. This is slightly more difficult.
Start by implementing the method in the same manner as the speak() method.
As for the method in the Pets class, you will need to iterate through the list of
dogs, then call the method itself.
Tom is walking!
Fletcher is walking!
Larry is walking!
Python
dogs = []
def walk(self):
for dog in self.dogs:
print(dog.walk())
# Parent class
class Dog:
# Class attribute
species = 'mammal'
is_hungry = True
# Instance method
def description(self):
return self.name, self.age
# Instance method
def speak(self, sound):
return "%s says %s" % (self.name, sound)
# Instance method
def eat(self):
self.is_hungry = False
def walk(self):
return "%s is walking!" % (self.name)
# Output
my_pets.walk()
Answer the following questions about OOP to check your learning progress:
1. What’s a class?
2. What’s an instance?
3. What’s the relationship between a class and an instance?
4. What’s the Python syntax used for defining a new class?
5. What’s the spelling convention for a class name?
6. How do you instantiate, or create an instance of, a class?
7. How do you access the attributes and behaviors of a class instance?
8. What’s a method?
9. What’s the purpose of self?
10. What’s the purpose of the __init__ method?
11. Describe how inheritance helps prevent code duplication.
12. Can child classes override properties of their parents?
Conclusion
You should now know what classes are, why you would want or need to use them,
and how to create both parent and child classes to better structure your programs.
Free Bonus: Click here to get access to a free Python OOP Cheat Sheet that
points you to the best tutorials, videos, and books to learn more about Object-
Oriented Programming with Python.
Watch Now This tutorial has a related video course created by the Real
Python team. Watch it together with the written tutorial to deepen your
understanding: Intro to Object-Oriented Programming (OOP) in Python
Python Tricks
Get a short & sweet Python Trick delivered to your inbox every couple of
days. No spam ever. Unsubscribe any time. Curated by the Real Python
team.
Email Address
Real Python Comment Policy: The most useful comments are those
written with the goal of learning from or helping out other readers—after
reading the whole article and all the earlier comments. Complaints and
insults generally won’t make the cut here.