Dziedziczenie w praktyce

Zacznijmy od przygotowania sobie pliku scratches i stworzenia klasy bazowej Animal. W naszej klasie umieścimy na razie jedynie prosty konstruktor (czyli __init__) oraz jedną z metod z diagramu, czyli increase_age. W każdej z nich umieścimy prosty print, który będzie nam wypisywał na konsolę informację o każdej z metod. Czyli w rezultacie nasza klasa przybierze postać:

class Animal:
   def __init__(self):
       print('Animal!')

   def increase_age(self):
       print('increase_age!')

Teraz powtórzmy wszystkie kroki dla klasy Mammal, którą umieścimy w tym samym pliku. Zgodnie z diagramem musimy w niej utworzyć metodę introduce_yourself.

class Mammal:
   def __init__(self):
       print('Mammal!')

   def introduce_yourself(self):
       print('introduce_yourself!')

W tym momencie może się pojawić pytanie:

Jak zrobić aby klasa Mammal dziedziczyła po klasie Animal?

Wystarczy dodać informację po jakiej klasie ma dziedziczyć klasa Mammal:

class Mammal(Animal):

czyli umieszczamy nazwę klasy bazowej w definicji klasy pochodnej (w nawiasach).

class Animal:
   def __init__(self):
       print('Animal!')

   def increase_age(self):
       print('increase_age!')


class Mammal(Animal):
   def __init__(self):
       print('Mammal!')

   def introduce_yourself(self):
       print('introduce_yourself!')

Można pod tym kodem wykonać polecenia, które pokażą, że możemy skorzystać z metody z klasy po której dziedziczymy czyli w naszym przypadku metody increase_age()

dog = Mammal()
dog.increase_age()

Co zakończy się wynikiem:

Mammal!
increase_age!

Dodatkowo, aby zainicjalizować zmienne z klasy bazowej w klasie podrzędnej musimy wywołać konstruktor klasy bazowej Animal.__init__(self) w konstruktorze klasy pochodnej.
Brzmi zawile ale zaraz zobaczymy to w akcji. Nasza klasa przyjmie następującą postać:

class Mammal(Animal):
   def __init__(self):
       Animal.__init__(self)
       print('Mammal!')

   def introduce_yourself(self):
       print('introduce_yourself!')

Co przy takim kodzie:

dog = Mammal()
dog.increase_age()

Da nam wynik:

Animal!
Mammal!
increase_age!

Jak widzimy dzięki temu obiekt utworzony z klasy Mammal wywołuje automatycznie konstruktor klasy Animal.

TIP: Dlaczego wywołanie konstruktora klasy bazowej Animal.__init__(self) jest opcjonalne? Wywołanie go zależy od dwóch rzeczy. Pierwszą jest czy konstruktor klasy bazowej wymaga podania argumentów. W naszym obecnym przypadku, konstruktor w klasie Animal def __init__(self) nie wymaga żadnych parametrów i robi tylko print(), dlatego możemy pominąć tą linię. Gdyby jednak konstruktor w klasie Animal przyjmował jakieś parametry np. name (czyli miał postać def __init__(self, name)), to musielibyśmy go wywołać w klasie pochodnej jako Animal.__init__(self, name) – tym przykładem zajmiemy się w kolejnych lekcjach.

Drugim warunkiem kiedy musimy wywołać konstruktor klasy bazowej, jest moment gdy w konstruktorze klasy bazowej inicjalizujemy jakieś zmienne bądź wykonujemy operacje, których wynik będzie potrzebny w klasie pochodnej. Poniżej prosty przykład obrazujący potencjalne problemy.

class Animal:
   def __init__(self):
       print('Animal!')
       self.some_value = 1

   def increase_age(self):
       print('increase_age!')


class Mammal(Animal):
   def __init__(self):
       print('Mammal!')
       print(self.some_value)

   def introduce_yourself(self):
       print('introduce_yourself!')


mammal_1 = Mammal()

Przy próbie uruchomienia powyższego skryptu otrzymamy błąd, gdyż zmienna self.some_value nie została zainicjalizowana:

AttributeError: 'Mammal' object has no attribute 'some_value'

Usuńmy kod:

dog = Mammal()
dog.increase_age()

Teraz zrobimy testy całościowe napisanego kodu. Na samym dole naszego skryptu dodajmy:

    Inicjalizację obiektu mammal_1, który będzie typu Mammal.
    Wywołanie metody introduce_yourself() na obiekcie mammal_1.
    Wywołanie metody increase_age() na obiekcie mammal_1.

Miejmy na uwadze, że pierwsza metoda introduce_yourself() pochodzi z klasy pochodnej (czyli Mammal), a increase_age() – z klasy bazowej Animal.

Cały kod przyjmie następującą postać:

class Animal:
   def __init__(self):
       print('Animal!')

   def increase_age(self):
       print('increase_age!')


class Mammal(Animal):
   def __init__(self):
       Animal.__init__(self)
       print('Mammal!')

   def introduce_yourself(self):
       print('introduce_yourself!')


mammal_1 = Mammal()
mammal_1.introduce_yourself()
mammal_1.increase_age()

Po jego uruchomieniu otrzymamy:

Animal!
Mammal!
introduce_yourself!
increase_age!

Jakie wnioski możemy z tego wyciągnąć?

    Możemy zaobserwować, że konstruktor klasy bazowej faktycznie został wywołany – pojawił się napis Animal! na konsoli.
    Metoda increase_age() jest bez problemu dostępna z klasy pochodnej.

Zapoznaliśmy się z odrobiną teorii oraz odrobiną praktyki z dziedziczeniem w roli głównej. Teraz przyszedł czas na krótkie zadania, które ma na celu utrwalić zdobytą wiedzę 😉

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *