Module lessons (2/4)
Inheritance
Inheritance lets you create a new class (the subclass) that inherits attributes and methods from an existing class (the base class), and can extend or override them.
Basic syntax
class Animale:
def __init__(self, nome):
self.nome = nome
def saluta(self):
return f"{self.nome} fa un verso"
class Cane(Animale): # Cane EREDITA da Animale
def saluta(self): # OVERRIDE del metodo
return f"{self.nome} dice WOOF!"
a = Animale("X")
c = Cane("Fido")
a.saluta() # 'X fa un verso'
c.saluta() # 'Fido dice WOOF!'Cane inherits __init__ from Animale without rewriting it.
super(): calling the base method
When you want to extend a base method (not completely replace it), use
super():
class Animale:
def __init__(self, nome):
self.nome = nome
class Cane(Animale):
def __init__(self, nome, razza):
super().__init__(nome) # delega alla base
self.razza = razza
c = Cane("Fido", "Labrador")
c.nome # 'Fido'
c.razza # 'Labrador'isinstance: type check
isinstance(c, Cane) # True
isinstance(c, Animale) # True (anche la base)
isinstance(c, str) # Falseisinstance(x, BaseClass) also recognizes all subclasses: this is what
makes inheritance useful for polymorphism.
animali = [Cane("Fido", "X"), Animale("Pippo")]
for a in animali:
print(a.saluta()) # ogni oggetto risponde a suo modoMRO (Method Resolution Order) — overview
When you have multiple inheritance, Python decides in which order to look for a method by following the MRO, computed with the C3 algorithm. For 95% of cases it is enough to know:
- it looks first in the instance,
- then in its class,
- then in the base classes in declaration order.
Cane.__mro__
# (<class 'Cane'>, <class 'Animale'>, <class 'object'>)object is the root of every class in Python 3.
Your turn
Given `class Vehicle: def __init__(self, brand): self.brand = brand`, define `Car(Vehicle)` with __init__(self, brand, model) that calls super().__init__ and stores self.model. Create `a = Car('Fiat', '500')` and evaluate `(a.brand, a.model)`.
Show hint
super().__init__(brand) then self.model = model.
Solution available after 3 attempts
Review exercise
Define `class Shape: def area(self): return 0` and `class Square(Shape)` with __init__(self, side) and area() that returns side * side. Create `q = Square(5)` and evaluate the tuple `(q.area(), isinstance(q, Shape))`.
Show hint
self.side * self.side.
Solution available after 3 attempts
Additional challenge
Create a class `Square` that inherits from the `Rectangle` class (defined below). The constructor of `Square` must take a single parameter `side` and pass it to `super().__init__(side, side)`. Instantiate a square with side `6` in `sq` and evaluate `sq.area()`.
Show hint
Declare class Square(Rectangle): and call super().__init__(side, side) in the constructor.
Solution available after 3 attempts