Základní aspekty
- Funkce
super()v Pythonu umožňuje volat metody nadřazené třídy z podřízené, což zjednodušuje implementaci dědičnosti a modifikaci metod. - Funkce
super()je úzce spjata s pořadím vyhledávání metod (MRO) v Pythonu, které specifikuje, v jakém pořadí se prohledávají nadřazené třídy, hledají-li se metody nebo atributy. - Běžnou praxí je používání
super()v konstruktorech tříd pro inicializaci společných atributů v nadřazené třídě a specifických v podřízené. Opomenutísuper()může vést k nechtěným důsledkům, jako je absence inicializace atributů.
Jedním ze stěžejních rysů Pythonu je jeho OOP paradigma, které se dá využít k modelování reálných entit a jejich vzájemných vazeb.
Při práci s třídami Pythonu se často setkáte s dědičností a potřebou modifikovat atributy nebo metody nadřazené třídy. Python nabízí funkci super(), která umožňuje volat metody nadřazené třídy z třídy podřízené.
Co je super() a proč ji potřebujeme?
Pomocí dědičnosti je možné vytvořit novou třídu v Pythonu, která přebírá vlastnosti existující třídy. Rovněž je možné přepsat metody nadřazené třídy v podřízené, a tím poskytnout alternativní implementaci. Často je však výhodné využít novou funkci jako rozšíření stávající, nikoli jako její náhradu. Právě v takových případech se funkce super() stává neocenitelnou.
Funkci super() lze použít k přístupu k atributům nadřazené třídy a k vyvolání jejích metod. super() je klíčová pro objektově orientované programování, neboť usnadňuje implementaci dědičnosti a modifikaci metod.
Jak super() funguje?
Interně je super() úzce spjata s pořadím vyhledávání metod (MRO) v Pythonu, které je založeno na algoritmu C3 linearizace.
Princip fungování super() je následující:
- Identifikace aktuální třídy a instance: Když je uvnitř metody podřízené třídy zavolána
super(), Python automaticky určí aktuální třídu (třídu, která obsahuje metodu volajícísuper()) a instanci této třídy (tedyself). - Identifikace nadřazené třídy:
super()přebírá dva argumenty – aktuální třídu a instanci – které se obvykle explicitně nepředávají. Tyto informace se využívají k určení nadřazené třídy, na kterou se deleguje volání metody. Tohoto dosahuje zkoumáním hierarchie tříd a MRO. - Volání metody v nadřazené třídě: Jakmile je nadřazená třída identifikována,
super()umožňuje volat její metody, jako by byly volány přímo z podřízené třídy. Umožňuje to rozšiřovat nebo upravovat metody, přičemž lze využít původní implementaci z nadřazené třídy.
Použití super() v konstruktoru třídy
Použití super() v konstruktoru třídy je běžné, jelikož je často třeba inicializovat společné atributy v nadřazené třídě a specifické atributy v podřízené třídě.
Jako demonstraci definujme třídu Otec, ze které bude dědit třída Syn:
class Otec:
def __init__(self, jmeno, prijmeni):
self.jmeno = jmeno
self.prijmeni = prijmeni
class Syn(Otec):
def __init__(self, jmeno, prijmeni, vek, konicek):
super().__init__(jmeno, prijmeni)
self.vek = vek
self.konicek = konicek
def ziskej_info(self):
return f"Jméno syna: {self.jmeno} {self.prijmeni},
Věk syna: {self.vek}, Koníček syna: {self.konicek}"
son = Syn("Pius", "Effiong", 25, "Hra na kytaru")
print(son.ziskej_info())
Uvnitř konstruktoru třídy Syn volání super().__init__() vyvolá konstruktor třídy Otec a předá mu jméno a příjmení jako parametry. To zajistí, že třída Otec bude moci správně nastavit atributy jména, a to i v objektu třídy Syn.
Pokud v konstruktoru třídy nezavoláte super(), konstruktor nadřazené třídy se neprovede. To může vést k nechtěným důsledkům, jako je absence inicializace atributů nebo neúplné nastavení stavu nadřazené třídy:
...
class Syn(Otec):
def __init__(self, jmeno, prijmeni, vek, konicek):
self.vek = vek
self.konicek = konicek
...
Pokud se nyní pokusíte zavolat metodu ziskej_info, dojde k vyvolání výjimky AttributeError, protože atributy self.jmeno a self.prijmeni nebyly inicializovány.

Použití super() v metodách třídy
super() lze použít i v jiných metodách, nejen v konstruktorech. Umožňuje to rozšířit nebo modifikovat chování metody nadřazené třídy.
class Otec:
def mluv(self):
return "Zdravím, jsem Otec"
class Syn(Otec):
def mluv(self):
pozdrav_rodice = super().mluv()
return f"Zdravím, jsem Syn\n{pozdrav_rodice}"
son = Syn()
pozdrav_syna = son.mluv()
print(pozdrav_syna)
Třída Syn dědí od třídy Otec a má svou vlastní metodu mluv. Metoda mluv ve třídě Syn používá super().mluv() pro volání metody mluv třídy Otec. To mu umožňuje zahrnout zprávu z nadřazené třídy a současně ji rozšířit o zprávu specifickou pro podřízenou třídu.

Opomenutí super() v metodě, která přepisuje jinou, vede k tomu, že se funkce z metody nadřazené třídy neprojeví. Výsledkem je úplná náhrada chování metody, což může způsobit chování, které nebylo zamýšleno.
Porozumění pořadí vyhledávání metod (MRO)
Pořadí vyhledávání metod (MRO) určuje, v jakém pořadí Python prohledává nadřazené třídy při přístupu k metodě nebo atributu. MRO pomáhá Pythonu rozhodnout, kterou metodu zavolat, když existuje více hierarchií dědičnosti.
class Nigérie():
def kultura(self):
print("Kultura Nigérie")
class Afrika():
def kultura(self):
print("Kultura Afriky")
Co se stane, když vytvoříte instanci třídy Lagos a zavoláte metodu kultura:
- Python začne hledat metodu
kulturav samotné tříděLagos. Pokud ji najde, zavolá ji. Pokud ne, přejde ke kroku dva. - Pokud metodu
kulturanenajde v tříděLagos, Python se podívá na základní třídy v pořadí, v jakém se objevují v definici třídy. V tomto případěLagosdědí nejprve zAfrikya poté zNigérie. Python tedy nejprve bude hledat metodukulturavAfrice. - Pokud nenajde metodu
kulturav tříděAfrika, Python ji bude hledat v tříděNigérie. Toto chování pokračuje, dokud nedosáhne konce hierarchie a vyvolá chybu, pokud nenajde metodu v žádné z nadřazených tříd.

Výstup ukazuje pořadí řešení metod pro Lagos, počínaje zleva doprava.
Běžná úskalí a osvědčené postupy
Při práci s super() existuje několik běžných úskalí, kterým je dobré se vyhnout.
- Mějte na paměti pořadí vyhledávání metod, zvláště v situacích s vícenásobnou dědičností. Pokud potřebujete používat složitou vícenásobnou dědičnost, měli byste se seznámit s C3 linearizačním algoritmem, který Python používá pro určení MRO.
- Vyhněte se cyklickým závislostem v hierarchii tříd, které mohou vést k nepředvídatelnému chování.
- Dokumentujte svůj kód srozumitelně, zvláště když používáte
super()ve složitých hierarchiích tříd. Zlepšíte tak srozumitelnost kódu pro ostatní vývojáře.
Používejte super() správně
Funkce super() v Pythonu je silným nástrojem při práci s dědičností a modifikací metod. Pochopení, jak super() funguje, a dodržování osvědčených postupů vám umožní vytvářet lépe udržovatelný a efektivnější kód ve vašich Python projektech.