Inheritance in Python
Inheritance lets a new class reuse the attributes and methods of an existing class. You name the parent class in parentheses, as in class Dog(Animal):, and the subclass can add methods, override inherited ones or extend them with super().
Key facts
class Dog(Animal):makesDoga subclass ofAnimal, so aDogobject can use every methodAnimaldefines.- A subclass with no
__init__of its own uses the parent's__init__. - A method defined in the subclass overrides the parent's method with the same name.
super().__init__(name)runs the parent's__init__from inside the subclass.isinstance(rex, Animal)isTruewhenrexis an instance of any subclass ofAnimal.
What is inheritance in Python?
Inheritance lets a new class reuse the attributes and methods of an existing class. The new class is called a subclass or child class, and the class it inherits from is its parent class or base class.
class Animal:
def __init__(self, name):
self.name = name
def describe(self):
print(self.name, "is an animal")
class Dog(Animal):
def bark(self):
print(self.name, "says woof")
rex = Dog("Rex")
rex.describe()
rex.bark()Rex is an animal Rex says woof
The parent goes in parentheses after the subclass name, so class Dog(Animal): makes Dog a subclass of Animal. Dog defines only bark(), yet rex.describe() works and Dog("Rex") sets the name.
When Python can't find a method or attribute on the object or its own class, it looks in the parent class next. That includes __init__, which is why Dog needs no __init__ of its own.
How do I override a method in Python?
Define a method with the same name in the subclass. Python finds the subclass's version first and runs it instead of the parent's, which is called overriding.
class Animal:
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return "Woof"
class Cat(Animal):
def speak(self):
return "Meow"
for pet in [Dog(), Cat(), Animal()]:
print(type(pet).__name__, pet.speak())Dog Woof Cat Meow Animal ...
The loop calls speak() on three objects without checking their types, and each answers with its own class's version. Using one method name across different classes like this is called polymorphism. type(pet).__name__ gives the class name as text.
What does super() do in Python?
super() lets a subclass call the parent class's version of a method. Its most common use is in a subclass's __init__, so the parent's __init__ can set up the object before the subclass adds its own attributes.
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
class Manager(Employee):
def __init__(self, name, salary, team):
super().__init__(name, salary)
self.team = team
boss = Manager("Ada", 90000, ["Grace", "Linus"])
print(boss.name, boss.salary, len(boss.team))Ada 90000 2
super().__init__(name, salary) runs Employee.__init__ on the new manager, so self.name and self.salary are set exactly as for any employee.
Pass the arguments the parent's __init__ expects, without self, because super() already knows which object it is working on.
class Employee:
def __init__(self, name):
self.name = name
def describe(self):
return f"{self.name}, employee"
class Manager(Employee):
def describe(self):
return super().describe() + " and manager"
print(Employee("Grace").describe())
print(Manager("Ada").describe())Grace, employee Ada, employee and manager
super() isn't limited to __init__. The manager's describe() adds " and manager" to the text super().describe() returns, instead of repeating the parent's code.
How do isinstance() and issubclass() work with subclasses?
isinstance() returns True for an object of the class or of any subclass of it. issubclass() asks the same question about two classes, as in issubclass(Dog, Animal).
class Animal:
pass
class Dog(Animal):
pass
rex = Dog()
print(isinstance(rex, Dog), isinstance(rex, Animal))
print(type(rex) == Animal)
print(issubclass(Dog, Animal), issubclass(Animal, Dog))True True False True False
A dog is an animal, so both isinstance() checks return True, but type(rex) == Animal is False, because the object's exact type is Dog. Use isinstance() when subclasses should pass the test too.
The data types lesson called bool a subtype, or subclass, of int, so isinstance(True, int) is True.
Animal and Dog contain only pass, the placeholder from the break and continue lesson, because a class body needs at least one statement.
How do I create a custom exception class in Python?
Write a class that inherits from Exception. Its body can be pass alone, because everything an exception needs comes from the parent class.
class InsufficientFundsError(Exception):
pass
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(f"need {amount - balance} more")
return balance - amount
try:
withdraw(50, 80)
except InsufficientFundsError as e:
print("Declined:", e)Declined: need 30 more
A custom exception lets callers catch this problem and nothing else. PEP 8 asks that exception names end in Error when the exception is an error.
Because the class inherits from Exception, an except Exception clause catches it too, along with the built-in exceptions from the errors and exceptions lesson.
Can a Python class inherit from more than one class?
Yes, and it is called multiple inheritance. List the parent classes in the parentheses, and when two of them define the same method, the one listed first wins.
class Flyer:
def move(self):
return "fly"
class Swimmer:
def move(self):
return "swim"
class Duck(Flyer, Swimmer):
pass
print(Duck().move())
print([cls.__name__ for cls in Duck.__mro__])fly ['Duck', 'Flyer', 'Swimmer', 'object']
Duck lists Flyer first, so move() comes from Flyer. Duck.__mro__ holds the order Python searches for methods and attributes, called the method resolution order or MRO, and the list comprehension collects each class's name.
The MRO ends with object, the built-in class every Python class inherits from. super() follows the MRO of the instance's class, so for a Duck, super() in a Flyer method reaches Swimmer's method next, though Swimmer isn't Flyer's parent.
Most classes need only one parent. Several parents are mainly used for mixins, small add-on classes that each supply a few methods.
What are the types of inheritance in Python?
Tutorials list five types of inheritance, which are single, multiple, multilevel, hierarchical and hybrid. They are shapes a family of classes can take rather than separate features, and all five use the same class Child(Parent): syntax.
| Type | Shape | Example |
|---|---|---|
| Single | One subclass of one parent | class Dog(Animal): |
| Multiple | One subclass of two or more parents | class Duck(Flyer, Swimmer): |
| Multilevel | A chain, where a subclass has its own subclass | class Puppy(Dog):, with Dog a subclass of Animal |
| Hierarchical | Several subclasses of one parent | class Dog(Animal): and class Cat(Animal): |
| Hybrid | A mix of these shapes | Two subclasses of Animal, plus a class that inherits from both |
Common mistakes with inheritance in Python
These four mistakes with Python inheritance leave a subclass missing attributes or behaving differently than you meant.
- AttributeError: 'Manager' object has no attribute 'name'. The subclass's own
__init__overrides the parent's, so the parent's setup never ran. Callsuper().__init__()with the parent's arguments. - TypeError: Employee.__init__() takes 2 positional arguments but 3 were given.
super().__init__(self, name)sends the object twice. Leaveselfout of the call. - Checking the type with ==.
type(rex) == AnimalisFalsefor aDog, so code that tests types this way rejects subclasses. Useisinstance(). - Inheriting where the is-a test fails. The test asks whether the subclass is a kind of the parent. A car is not an engine, yet a
Carthat inherits fromEnginegets every engine method. Store anEngineobject in an attribute instead, which is called composition.
The program below forgets to call super().__init__(). Add super().__init__(name) as the first line of the manager's __init__ and run it again.
class Employee:
def __init__(self, name):
self.name = name
class Manager(Employee):
def __init__(self, name, team):
self.team = team
boss = Manager("Ada", ["Grace"])
print(boss.name)Traceback (most recent call last):
File "main.py", line 10, in <module>
print(boss.name)
^^^^^^^^^
AttributeError: 'Manager' object has no attribute 'name'Exercise
Change Square.__init__() so it calls super().__init__(side, side), and the program prints 16. The starter stops with an AttributeError, because the rectangle's __init__ never runs and the square has no width.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, side):
self.side = side
print(Square(4).area())
16
Show the solution
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)
print(Square(4).area())
Quiz
This quiz has 5 questions. Pick an answer to see why it is right or wrong.
-
1What does this program print?
class A: def hello(self): return "A" class B(A): def hello(self): return "B" + super().hello() print(B().hello())B overrides hello(), and its version puts "B" first. It then adds the "A" that super().hello() returns, so the program prints BA, not AB or B alone.
-
2What does this program print?
class Animal: pass class Dog(Animal): pass d = Dog() print(isinstance(d, Animal), type(d) == Animal)isinstance() accepts subclasses, so a Dog counts as an Animal. type() gives the exact type, Dog, so comparing it with Animal gives False.
-
3Dog inherits from Animal, and only Animal defines __init__(self, name). What happens when you call Dog("Rex")?
Python looks up __init__ like any other method, so it finds Animal's version and runs it with "Rex", and the dog gets every attribute that __init__ sets. If Animal's __init__ took no name, the same call would raise a TypeError instead.
-
4What does this program print?
class Flyer: def move(self): return "fly" class Swimmer: def move(self): return "swim" class Duck(Swimmer, Flyer): pass print(Duck().move())Swimmer is listed first, so Python finds its move() before Flyer's. Two parents with the same method are allowed, and the order in the parentheses decides which one runs.
-
5Which line defines Manager as a subclass of Employee?
The parent class goes in parentheses after the new class name, so Employee(Manager) would make Employee the subclass instead. The word extends is a keyword in other languages, not in Python.























