Inheritance
Building one class on top of another: the derived class inherits the base class’s methods and can extend or override them.
Example
#class User:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hi, I'm {self.name}"
def role(self):
return "user"
class Mentor(User):
def role(self):
return "mentor"
def review(self, task):
return f"{self.name} is reviewing task {task}"
darwin = Mentor("Darwin")
print(darwin.greet())
print(darwin.role())
print(darwin.review("7_3"))
print(isinstance(darwin, User), issubclass(Mentor, User))Definition and usage
#Inheritance lets you create a new class based on an existing one. You give the base class in parentheses after the name: class Mentor(User). The derived class automatically gets all the methods and attributes of the base class, so you only write what is new or different in it.
A method with the same name in the derived class overrides the base version. Python looks for a method first in the object’s own class, then in its base class, and so on, up to the built-in object class that every class inherits from. The attribute __mro__ shows this order (MRO, for method resolution order). From an overridden method, you call the base version through super().
The function isinstance(object, Class) returns True for objects of derived classes too, while issubclass(A, B) checks the relationship between the classes themselves. This means code written for the base class works with every derived class, and each one can respond to the same call in its own way. This is called polymorphism.
A class can inherit from several classes at once (class Quiz(Timed, Scored)), which is useful for small classes that each add one capability, so-called mixins. Use inheritance when an "is-a" relationship holds: a mentor is a user. When an object merely "has" another object, for example a course has a list of lessons, store it as an attribute instead. This approach is called composition.
Syntax
#class Base:
...
class Derived(Base):
...
class Derived(Base1, Base2):
...More examples
#class Task:
def __init__(self, exp):
self.exp = exp
def reward(self):
return self.exp
class BonusTask(Task):
def reward(self):
return self.exp * 2
class Tutorial(Task):
def reward(self):
return 0
tasks = [Task(10), BonusTask(10), Tutorial(10)]
print([task.reward() for task in tasks])
print(sum(task.reward() for task in tasks))class Exercise:
def describe(self):
return "task"
class Timed(Exercise):
def describe(self):
return "a timed task"
class Scored(Exercise):
def describe(self):
return "a scored task"
class Quiz(Timed, Scored):
pass
print(Quiz().describe())
print([cls.__name__ for cls in Quiz.__mro__])class CodeWorldsError(Exception):
pass
class NoFuelError(CodeWorldsError):
pass
class LockedWorldError(CodeWorldsError):
pass
for error in [NoFuelError("Out of fuel"), LockedWorldError("World 9 is locked")]:
try:
raise error
except CodeWorldsError as caught:
print(type(caught).__name__, "->", caught)Good practices
#- Only inherit when an object of the derived class truly "is" an object of the base class. If it merely uses it, store it as an attribute instead.
- Avoid deep hierarchies. Two or three levels are usually enough, and each additional one makes it harder to tell where a given method comes from.
- Derive your custom exceptions from a shared base class. A single
excepton the base class then handles the whole family of errors.
Related entries
#- classDefines a class: a template for objects that combines data with the functions that act on it.
- super()Calls a method of the base class from inside the derived class, most often the __init__ constructor.
- isinstance()Checks whether an object is of a given type, or of a subtype of it.
- __init__()A method called automatically when an object is created. It stores the object’s initial data, its attributes.
- raiseRaises an exception, signaling an error or a disallowed situation.
Spotted a mistake or missing an example? Write to us.