Lekcje modułu (2/4)
Dziedziczenie
Dziedziczenie (inheritance) pozwala utworzyć nową klasę (podklasę), która przejmuje atrybuty i metody istniejącej już klasy (klasy bazowej), i może je rozszerzać lub nadpisywać (override).
Podstawowa składnia
class Animale:
def __init__(self, nome):
self.nome = nome
def saluta(self):
return f"{self.nome} fa un verso"
class Cane(Animale): # Cane DZIEDZICZY po Animale
def saluta(self): # NADPISANIE metody (override)
return f"{self.nome} dice WOOF!"
a = Animale("X")
c = Cane("Fido")
a.saluta() # 'X fa un verso'
c.saluta() # 'Fido dice WOOF!'Klasa Cane dziedziczy konstruktor __init__ z klasy Animale bez potrzeby przepisywania go.
super(): wywołanie metody z klasy bazowej
Gdy chcesz rozszerzyć zachowanie metody bazowej (a nie zastąpić ją całkowicie), użyj
funkcji super():
class Animale:
def __init__(self, nome):
self.nome = nome
class Cane(Animale):
def __init__(self, nome, razza):
super().__init__(nome) # delegacja do klasy bazowej
self.razza = razza
c = Cane("Fido", "Labrador")
c.nome # 'Fido'
c.razza # 'Labrador'isinstance: sprawdzanie typu
isinstance(c, Cane) # True
isinstance(c, Animale) # True (także klasa bazowa)
isinstance(c, str) # FalseOperacja isinstance(x, KlasaBazowa) rozpoznaje również wszystkie podklasy: to właśnie sprawia,
że dziedziczenie jest niezwykle użyteczne w implementacji polimorfizmu.
animali = [Cane("Fido", "X"), Animale("Pippo")]
for a in animali:
print(a.saluta()) # każdy obiekt reaguje we własny sposóbMRO (Method Resolution Order) — przegląd
W przypadku dziedziczenia wielokrotnego, Python decyduje, w jakiej kolejności szukać metody, korzystając z mechanizmu MRO (wyliczanego algorytmem C3). W 95% przypadków wystarczy wiedzieć, że szukanie odbywa się:
- najpierw w instancji obiektu,
- następnie w jego klasie,
- następnie w klasach bazowych w kolejności ich deklaracji.
Cane.__mro__
# (<class 'Cane'>, <class 'Animale'>, <class 'object'>)object jest klasą bazową dla wszystkich klas w Pythonie 3.
Spróbuj sam
Mając daną `class Vehicle: def __init__(self, brand): self.brand = brand`, zdefiniuj klasę `Car(Vehicle)` z konstruktorem __init__(self, brand, model) wywołującym super().__init__ i zapisującym self.model. Utwórz `a = Car('Fiat', '500')` i oceń krotkę `(a.brand, a.model)`.
Pokaż wskazówkę
Wywołaj super().__init__(brand) a potem self.model = model.
Rozwiązanie dostępne po 3 próbach
Ćwiczenie powtórzeniowe
Zdefiniuj `class Shape: def area(self): return 0` oraz klasę `Square(Shape)` z konstruktorem __init__(self, side) i metodą area() zwracającą side * side. Utwórz `q = Square(5)` i oceń krotkę `(q.area(), isinstance(q, Shape))`.
Pokaż wskazówkę
Zwróć self.side * self.side.
Rozwiązanie dostępne po 3 próbach
Dodatkowe wyzwanie
Utwórz klasę `Square` dziedziczącą po klasie `Rectangle` (zdefiniowanej poniżej). Konstruktor klasy `Square` musi przyjmować pojedynczy parametr `side` i przekazywać go do `super().__init__(side, side)`. Utwórz obiekt kwadratu o boku `6` w zmiennej `sq` i oceń `sq.area()`.
Pokaż wskazówkę
Zadeklaruj klasę Square(Rectangle): i wywołaj super().__init__(side, side) w konstruktorze.
Rozwiązanie dostępne po 3 próbach