Dziedziczenie

Budowanie klasy na bazie innej: klasa pochodna przejmuje metody klasy bazowej i może je rozszerzać lub nadpisywać.

Na tej stronie

Przykład

#
Python
class User:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Cześć, jestem {self.name}"

    def role(self):
        return "użytkownik"

class Mentor(User):
    def role(self):
        return "mentor"

    def review(self, task):
        return f"{self.name} sprawdza zadanie {task}"

darwin = Mentor("Darwin")
print(darwin.greet())
print(darwin.role())
print(darwin.review("7_3"))
print(isinstance(darwin, User), issubclass(Mentor, User))
Wynikzapisany wynik, możesz go sprawdzić
Cześć, jestem Darwin
mentor
Darwin sprawdza zadanie 7_3
True True

Definicja i zastosowanie

#

Dziedziczenie pozwala utworzyć nową klasę na podstawie istniejącej. Klasę bazową podajesz w nawiasie po nazwie: class Mentor(User). Klasa pochodna automatycznie dostaje wszystkie metody i atrybuty klasy bazowej, więc piszesz w niej tylko to, co nowe albo inne.

Metoda o tej samej nazwie w klasie pochodnej nadpisuje wersję bazową. Python szuka metody najpierw w klasie obiektu, potem w jej klasie bazowej i tak dalej, aż do wbudowanej klasy object, po której dziedziczy każda klasa. Tę kolejność (MRO, od method resolution order) pokazuje atrybut __mro__. Z nadpisanej metody wersję bazową wywołasz przez super().

Funkcja isinstance(obiekt, Klasa) zwraca True także dla obiektów klas pochodnych, a issubclass(A, B) sprawdza relację między samymi klasami. Dzięki temu kod napisany dla klasy bazowej działa z każdą klasą pochodną, a każda z nich może na swój sposób reagować na to samo wywołanie. To zjawisko nazywa się polimorfizmem.

Klasa może dziedziczyć po kilku klasach naraz (class Quiz(Timed, Scored)), co przydaje się przy małych klasach dodających jedną umiejętność, tzw. mixinach. Dziedziczenia używaj, gdy zachodzi relacja „jest”: mentor jest użytkownikiem. Gdy obiekt tylko „ma” inny obiekt, np. kurs ma listę lekcji, zapisz go jako atrybut. Takie podejście nazywa się kompozycją.

Składnia

#
Składnia
class Bazowa:
    ...

class Pochodna(Bazowa):
    ...

class Pochodna(Bazowa1, Bazowa2):
    ...

Więcej przykładów

#
Polimorfizm: jedna pętla, różne klasy
Python
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))
Wynikzapisany wynik, możesz go sprawdzić
[10, 20, 0]
30
Kolejność wyszukiwania metod (MRO)
Python
class Exercise:
    def describe(self):
        return "zadanie"

class Timed(Exercise):
    def describe(self):
        return "zadanie na czas"

class Scored(Exercise):
    def describe(self):
        return "zadanie za punkty"

class Quiz(Timed, Scored):
    pass

print(Quiz().describe())
print([cls.__name__ for cls in Quiz.__mro__])
Wynikzapisany wynik, możesz go sprawdzić
zadanie na czas
['Quiz', 'Timed', 'Scored', 'Exercise', 'object']
Rodzina własnych wyjątków
Python
class CodeWorldsError(Exception):
    pass

class NoFuelError(CodeWorldsError):
    pass

class LockedWorldError(CodeWorldsError):
    pass

for error in [NoFuelError("Brak paliwa"), LockedWorldError("Świat 9 jest zablokowany")]:
    try:
        raise error
    except CodeWorldsError as caught:
        print(type(caught).__name__, "->", caught)
Wynikzapisany wynik, możesz go sprawdzić
NoFuelError -> Brak paliwa
LockedWorldError -> Świat 9 jest zablokowany

Dobre praktyki

#
  • Dziedzicz tylko wtedy, gdy obiekt klasy pochodnej naprawdę „jest” obiektem klasy bazowej. Jeśli jedynie z niego korzysta, zapisz go jako atrybut.
  • Unikaj głębokich hierarchii. Dwa, trzy poziomy zwykle wystarczą, a każdy kolejny utrudnia ustalenie, skąd pochodzi dana metoda.
  • Własne wyjątki wyprowadzaj ze wspólnej klasy bazowej. Jeden except na klasę bazową obsłuży wtedy całą rodzinę błędów.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.