🥕 Dziedziczenie
Wstęp
Kluczowa cecha programowania obiektowego, pozwala na tworzenie nowych klas na bazie istniejących. Umożliwia to wykorzystanie już zdefiniowanych atrybutów i metod w nowej klasie, co sprzyja oszczędności kodu i ułatwia jego zarządzanie.
Uwaga
Zwróć uwagę w poniższym przykładzie jak wygląda wywoływanie konstruktorów klas nadrzędnych.
class Pojazd: # Klasa bazowa
def __init__(self, marka):
self.marka = marka
def uruchom(self):
print(f"{self.marka} jest uruchamiany.")
class Samochod(Pojazd): # Klasa pochodna
def __init__(self, marka, model):
super().__init__(marka) # Wywołanie konstruktora klasy bazowej
self.model = model
Wyszukiwanie dziedziczenia
Gdy obiekt wywołuje metodę lub uzyskuje dostęp do atrybutu, Python rozpoczyna proces wyszukiwania tego elementu zgodnie z tzw. MRO (Method Resolution Order) - to algorytm wyszukiwania dziedziczenia:
- Najpierw sprawdzana jest klasa, do której należy dany obiekt (czyli klasa pochodna).
- Następnie sprawdzane są klasy bazowe (superklasy) w kolejności od najbliższej do najdalszej.
- Jeśli Python znajdzie odpowiedni element w pierwszej napotkanej klasie, kończy poszukiwanie.
Klasy mogą także dziedziczyć po więcej niż jednej klasie - nazywamy to dziedziczeniem wielokrotnym. W takim wypadku wyszukiwanie z pkt. 2 odbywa się od najbliższej klasy bazowej (wymieniona jako pierwsza przy definiowaniu dziedziczenia) do najdalszej.
class Pojazd:
def uruchom(self):
print("Pojazd jest uruchamiany.")
class Silnik:
def uruchom(self):
print("Silnik jest uruchamiany.")
class Samochod(Pojazd, Silnik):
pass
moj_samochod = Samochod()
moj_samochod.uruchom()
## Zwraca: Pojazd jest uruchamiany.
Aby sprawdzić kolejność MRO, można użyć metody .__mro__ lub funkcji help():
print(Samochod.__mro__)
Jeśli metoda lub atrybut nie istnieje ani w klasie pochodnej, ani w żadnej z klas bazowych, Python zgłasza błąd, np. AttributeError.
Nadpisywanie (overriding)
Process, w którym klasa pochodna definiuje własną wersję metody o tej samej nazwie, co metoda w klasie bazowej. Dzięki temu klasa pochodna może zmienić lub rozszerzyć działanie odziedziczonej metody, dostosowując ją do własnych potrzeb.
Uwaga
Zwróć uwagę w poniższym przykładzie jak wygląda specjalizacja odziedziczonych metod.
class Pojazd:
def uruchom(self):
print("Pojazd jest uruchamiany.")
class Samochod(Pojazd):
def uruchom(self): # Nadpisywanie metody uruchom
print("Samochód jest uruchamiany szybciej!")
super().uruchom() # Wywołanie oryginalnej metody klasy bazowej
moj_samochod = Samochod()
moj_samochod.uruchom()