You have the eyes of your mother. One could say, you “inherited” the eyes of your mother. As you may have guessed, this article is about inheritance in Python.
Inheritance is one of the most important features of object orientation. It’s a simple and intuitive concept but even advanced coders circumvent using inheritance because they have this latent feeling of not understanding it 100%. This harms their ability to write clean and effective code, and--ultimately — harms their ability to operate to their full potential. Do you think you could do more to live up to your potential? Good. Then, let’s start learning inheritance in Python.
As a small gift of appreciation for reading this tutorial and improving your programming skills, you’ll get a free PDF download of my Object Orientation Cheat Sheet at the end of this tutorial.
What is Inheritance in Python?
Inheritance allows you to define a class that inherits all methods and properties from another class.
- Parent class, also denoted as base class, is the class you inherit from. In Python, every class can be a parent class.
- Child class, also denoted as derived class, inherits from the Parent class. In Python, you can create a child class that inherits all methods and attributes from the Parent using the
class Child(Parent)syntax with the parent class enclosed in parentheses.
Here’s the minimal syntax showing how to derive a child class from a parent class using the highlighted parentheses method:
class Parent: pass class Child(Parent): pass
In the following example, you create two classes
Parent has one method
p() that prints the string
'from parent' when executed.
Child has method
c() that prints the string
'from child' and the inherited method
p() from the
# Define parent and child classes class Parent: def p(self): return 'from parent' # Child inherits method p() from parent class Child(Parent): def c(self): return 'from child' # Create parent instance and run method parent = Parent() print(parent.p()) # Create child instance and run methods child = Child() print(child.p()) print(child.c())
The output is:
from parent from parent from child
You can see that the child inherits all methods and, not shown, all attributes from the parent class. This can save you a lot of redundancies in practice.
Puzzle and Negative Example
Let’s have a look at a bad example NOT using inheritance. Keep your code understanding skills fresh by solving the puzzle first before you read on.
class Human: def __init__(self, name, ff, iq): self.name = name self.ff = ff # = facebook friends self.iq = iq def befriend(self, other): self.ff += 1 other.ff += 1 def learn(self): self.iq += 1 class Wizard: def __init__(self, name, ff, iq, mana): self.name = name self.ff = ff # = facebook friends self.iq = iq self.mana = mana def befriend(self, other): self.ff += 1 other.ff += 1 def learn(self): self.iq += 1 def magic_friends(self, num): self.ff += num if self.mana>0 else 0 self.mana -= 100 vernon = Human("Vernon", 0, 80) tom = Wizard("Tom", 666, 130, 100) dumbledore = Wizard("Albus", 999, 189, 100) dumbledore.befriend(tom) dumbledore.befriend(vernon) dumbledore.magic_friends(100) print("Friends Vernon: " + str(vernon.ff)) print("Friends Tom: " + str(tom.ff)) print("Friends Dumbledore: " + str(dumbledore.ff))
Before you read on, I have two questions for you:
- What is the output of the above code snippet?
- What’s your idea of making this code more concise?
What is the output of the above code snippet?
Let’s start with the first question. We create two classes
Wizards. Both have very similar methods and attributes. The only difference is that the
Wizard class has one additional attribute
self.mana and one additional method
magic_friends. Both methods
magic_friends modify the instance attribute
ff. With a magic trick, Dumbledore gains 100 additional friends, in addition to Tom and Vernon.
Thus, the result is:
""" Friends Vernon: 1 Friends Tom: 667 Friends Dumbledore: 1101 """
How to Improve This Code?
Regarding the second question, I have already indicated the problem: there are huge redundancies between the two classes
Wizard. Most methods and attributes are exactly the same. The reason is that, conceptually, a
Wizard is also
Human. And every human needs to have an IQ, a Facebook account, and a name (as you know).
In other words: Every
Wizard is a
Human but not every
Human is a
How can we express this fact in Python object orientation?
The answer is inheritance.
We create a class
Human and a class
Wizard. The class
Wizard is the “child class” of the “parent class”
Human. In this way, the child class
Wizard “inherits” every attribute and method from the parent class
Human. This saves us all the redundant definitions and initializations in the
See the example:
class Human: def __init__(self, name, ff, iq): self.name = name self.ff = ff # = facebook friends self.iq = iq def befriend(self, other): self.ff += 1 other.ff += 1 def learn(self): self.iq += 1 class Wizard(Human): def __init__(self, name, ff, iq, mana): super().__init__(name, ff, iq) self.mana = mana def magic_friends(self, num): self.ff += num if self.mana>0 else 0 self.mana -= 100 vernon = Human("Vernon", 0, 80) tom = Wizard("Tom", 666, 130, 100) dumbledore = Wizard("Albus", 999, 189, 100) dumbledore.befriend(tom) dumbledore.befriend(vernon) dumbledore.magic_friends(100) print("Friends Vernon: " + str(vernon.ff)) print("Friends Tom: " + str(tom.ff)) print("Friends Dumbledore: " + str(dumbledore.ff)) dumbledore.learn() print("IQ Dumbledore: " + str(dumbledore.iq))
The result is exactly the same as above. As you can see in the last two lines, Dumbledore can still call the method
learn() — even though it is not defined in the
Wizard class. The reason is that the
Wizard class inherits all methods and attributes from the
Can you find where we define the inheritance in the code?
One final note: in the constructor of the
Wizard class, we call the constructor of the parent class using
"super()". This initializes the variables in exactly the same way as the parent constructor from the
Calling the Constructor of the Parent Class with super()
super() method returns a temporary object of the superclass to help you access its methods. Its purpose is to avoid using the base class name explicitly. It also enables your class to inherit from multiple base classes.
The idea is simple: use
super() to call the methods defined in the parent classes—whether your child class inherits from one or multiple base classes. See the graphic:
Need me to guide you through this example? Watch the explainer video next!
Next, you’ll learn about both cases by example!
Simple Example 1: super() with Single Inheritance
Inheritance in object-oriented programming allows you to create a class hierarchy where one child class inherits all methods from another parent class. This simplifies the development of large software projects and avoids redundant code. You can learn more about the concept of inheritance in our blog tutorial here.
For example, the following code defines the parent class
Organism and the child class
Human. The child class uses
super() to run the constructor method of the parent class.
class Organism: def __init__(self): print('I live') class Human(Organism): def __init__(self): print('I am human') super().__init__() alice = Human()
The output is:
I am human I live
Here you call the base class Organism using the following code:
A semantically equivalent code call would be:
You call the
__init__() method on the base class
Organism and pass a reference to the calling instance as an argument. This way, you could also modify the internal attributes of the
self instance within the base class’ constructor.
However, the advantage of using
super().__init__() compared to
ParentClass.__init__(self) is that you avoid calling the parent class explicitly. This is advantageous because it decouples the child from the parent class. For example, if you changed the name of the
NewParentClass, the method using
super() would be superior because it would still work while the method using
ParentClass.__init__(self) would throw an error.
Example 2: super() with Multiple Inheritance
One of Python’s unique features compared to other programming languages is that it allows multiple inheritance.
Multiple inheritance means that a class can inherit from multiple parents. For example, a class
Human can inherit from two parent classes:
Thinker. Say, you define a method
live() in Organism and
think() in Thinker. If a Human object inherits from both classes, it can call
think() at the same time! You use the
super() method to call those functions:
class Organism: def live(self): print('I live') class Thinker: def think(self): print('I think') class Human(Organism, Thinker): def __init__(self): print('I am human') super().live() super().think() alice = Human()
The output is:
I am human I live I think
I should mention that in this example, you could also have called
self.think() in the class
Human instead of
super().think(). The output would be the same in both cases. In practice, you’d use the former for instance methods and the latter for class methods. The difference between both is explained in our blog tutorial here.
Python OOP Cheat Sheet
Congratulations, you read through the whole article. Here’s a small reward for your effort: my object-orientation terminology cheat sheet!
You can also check out my in-depth Python cheat sheet tutorial with lots of free PDF cheat sheets about various topics in Python such as keywords, data structures, lists, sets, NumPy, pandas, and many more. Simply put your email here and download my free cheat sheets:
Where to Go From Here?
Strategy beats tactics in the long run. You need to have a learning strategy in place to master Python. Do you?
If not, get a quick win by downloading our popular Python cheat sheets (high-res PDF), as well as the long-term solution to your problem (almost daily Python lessons). It’s 100% free. No Spam. Guaranteed.
While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.
To help students reach higher levels of Python success, he founded the programming education website Finxter.com. He’s author of the popular programming book Python One-Liners (NoStarch 2020), coauthor of the Coffee Break Python series of self-published books, computer science enthusiast, freelancer, and owner of one of the top 10 largest Python blogs worldwide.
His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.