Dědičnost

Třídy mají jednu zajímavou vlastnost - mohou od sebe dědit. Uvažujme třeba, že bychom chtěli vytvořit novou třídu Manager, která reprezentuje zaměstnance, který má nějaké podřízené. U manažera bychom rádi měli seznam jeho podřízených. Jinak se samozřejmě manažer od ostatních nijak neliší - má jméno, název pozice i nárok na dovolenou.

Ideální by tedy bylo mít kopii třídy Employee, která bude mít nový atribut subordinates (seznam jeho podřízených). Samozřejmě bychom mohli kód třídy Employee zkopírovat a upravit, ale díky dědičnosti to můžeme udělat i lépe. Můžeme novou třídu Manager postavit na základě třídy Employee. Třída Manager tak zdědí od třídy Employee všechny atributy a funkce, a my jen přidáme nebo upravíme, co potřebujeme.

Napíšeme tedy novou funkci __init__, protože potřebujeme vytvořit atribut subordinates jako prázdný list. Poté přidáme funkci addSubordinate, která k listu připojí jednoho podřízeného.

class Manager(Employee):
  def addSubordinate(self, newSubordinate):
    self.subordinates.append(newSubordinate)

  def __init__(self, name, position):
    self.name = name
    self.position = position
    self.remainingHolidayDays = 25
    self.subordinates = []

Zkusíme si nyní vytvořit objekt, který bude reprezentovat manažera. U objektu vyzkoušíme, zda u ní funguje metoda getInfo. Tuto metodu jsme pro třídu Manager neprogramovali, měla by být zděděná od třídy Employee.

boss = Manager("Marian Přísný", "vedoucí konstrukčního oddělení")
print(boss.getInfo())

Zatím vše funguje, přesto můžeme náš kód ještě vylepšit. Ve funkci __init__ musíme poněkud nešikovně opisovat tři řádky, které nastavují hodnoty atributů. Přitom ty stejné řádky už jsou v třídě Employee. Mohli bychom nějak existující kód z třídy Employee upravit?

Ve skutečnosti ano. Využijeme k tomu speciální funkci super, kterou se odvoláme na mateřskou třídu aktuální třídy. Následně můžeme použít tečku a zavolat funkci __init__. Tím tedy voláme funkci __init()__ mateřské třídy Employee.

class Manager(Employee):
  def addSubordinate(self, newSubordinate):
    self.subordinates.append(newSubordinate)

  def __init__(self, name, position):
    super().__init__(name, position)
    self.subordinates = []

Třída Manager se tak o něco zkrátila a zpřehlednila.

Náš kód už bychom mohli spustit, ale nemohli bychom pořádně otestovat, že přidávání podřízených funguje. My je totiž ukládáme, ale zatím nemáme funkci pro jejich vypsání. Přidáme tedy funkci getSubordinates, která vrátí informaci o podřízených manažera.

class Manager(Employee):
  def addSubordinate(self, newSubordinate):
    self.subordinates.append(newSubordinate)

  def getSubordinates(self):
    subordinates = f"{self.name} má tyto podřízené: "
    for item in self.subordinates:
      subordinates += item.name + ", "
    return subordinates
  
  def __init__(self, name, position):
    super().__init__(name, position)
    self.subordinates = []

Nyní můžeme vše vyzkoušet. Vedoucímu, který je uložený v proměnné boss, přiřadíme dva podřízené. Následně si zkusíme proměnné vypsat.

frantisek = Employee("František Novák", "konstruktér")
klara = Employee("Klára Nová", "konstruktérka")

boss = Manager("Marian Přísný", "vedoucí konstrukčního oddělení")
boss.addSubordinate(frantisek)
boss.addSubordinate(klara)
print(boss.getSubordinates())

Náš program tedy vytvoří tři objekty - dva zaměstnance a jednoho manažera. Manažerovi jsme přiřadili zaměstnance jako podřízené. A vidíme, že naše akce proběhla správně, protože tito dva zaměstnanci se objevili ve výpisu podřízených.

Příklady na dědičnost

1

Balík

zapni hlavu

Pokračuj ve své práci pro zásilkovou společnost. Společnost nově doručuje i cenné balíky, které mají zadanou určitou hodnotu.

  • Vytvoř třídu ValuablePackage, která dědí od třídy Package. ValuablePackage má navíc atribut value, ostatní atributy dědí od třídy Package.
  • Atribut value nastav pomocí funkce __init__. Ostatní parametry předej funkci __init__ třídy Package.
  • Vytvoř si alespoň jeden objekt a zkus volání jeho funkcí.
2

Částečný úvazek

zapni hlavu

Naše firma se rozhodla zaměstnávat i pracovníky na částečné úvazky, pro které bude vytvořena zvláštní třída. Vytvoř novou třídu PartTimeEmployee, která bude dědit od třídy Employee a bude mít navíc atribut workload (float), který reprezentuje velikost úvazku oproti plnému. Přidej informaci o úvazku k výpisu informací do funkce getInfo.

Bonusová cvičení
Nepovinné úložky, které můžete řešit pokud máte chuť na větší výzvu nebo si chcete látku procvičit víc do hloubky.
3

Řidič

smrt v přímém přenosu

Pokračuj ve své práci pro zásilkovou společnost. Společnost nyní eviduje jednotlivé řidiče a eviduje balíky, které má každý řidič doručit.

  • Vytvoř třídu Driver, která má dva atributy: name (jméno řidiče) a packageList (seznam balíků k doručení, na začátku je prázdný).
  • Přidej třídě funkci assignPackage, která bude mít jeden parametr - package (balík k doručení, může se jednat i o cenný balík).
  • Funkce nejprve zkontroluje, zda balík již nebyl doručen. Pokud ano, vypíše funkce text: "Nelze přiřadit, balík již byl doručen."
  • Pokud balík ještě nebyl doručen, je přidán do seznamu balíků packageList (použij funkci append).
  • U řidiče chceme sledovat, kolik by měl ještě doručit balíků. Napiš funkci remainingPackages, která vrátí počet balíků, které má řidič přiřazené a ještě je nedoručil.