podpora ve většině OOP jazyků
Co je společné pro dědičnost: týká se tříd (nikoliv objektů), je to vztah mezi třídami
dědění (převzetí něčeho z bázové třídy)
1.1 dědění metod
bázová třída -> odvození -> odvozená třída odvozená třída dědí všechny metody bázové třídy (lze je použít nejen pro instance bazové, ale i odvozené)
class X(list):
pass
x = X()
len(x) # dědí __len__
x.append(2) # dědí append
1.2. dědění datových členů
musí být děděny i datové členy (je nutné pro funkci zdědděných metod)
!!! tento mechanismus je v Pythonu složitější
class A:
def __init__(self, data):
self.data = data
def print(self):
print(self.data)
class B(A):
pass
v zásadě funguje jen pokud nevyžadujeme nový konstruktor
přidání a předefinování 2.1 přidání metod
lze přidat další metody
2.2 přidání nových datových členů (objekt se rozšíří o datové členy)
2.3 je nutné vytvořit nový konstruktor (je nutné inicializovat nové datové členy nelze použít původní konstruktor (zastínění resp. náhrada)
class A:
def __init__(self, data):
self.data = data
def print(self):
print(self.data)
class B(A):
def __init__(self, data, description): # zastíní původní
# je nutné volat konstruktor předka (aby inicializoval zdědené)
super().__init__(data)
self.description = description
def get_description(self): # přidaná metoda
return self.description
def print(self):
print(f"{self.data} {self.description}")
# byla zděděna metoda print
2.4 je možno předefinovat metody (override)
původní metodu nahradíme jinou (musí mít stejné jméno)
polymorfismus: schopnost vytvořit kód, který umožňuje využívat objekty různých tříd
x::Mecislo x + 1 1 + x
a je int,double,str, všechny, které definují add OR b je int,double,str všechny, které poddporuji radd
duck polymorfismus: v Pythonu nejsou důležité třídy, ale poskytované metody
x.f()
duck: musí podporovat tu metodu musí plnit kontrakt (chování metody) kontrakt: precondition (co musí splňovat parametry) postcondition (návratová hodnota, nový stav) invariant (co metoda nezmění) jaké výjimky vzniknou
dědičnost a polymorfismus
a = A(5)
isinstance(a, A) # určitě True
b = B(8, "popisek")
isinstance(b, A) # instance odvozené je zároveň i instancí bázové třída
ale prekticky je dulěžitější reálná zastupitelnost:
jestliže použujeme objekty odvozené na místě, kde jsou očekávány objekty bázové, tak nesmíme poznat rozdíl (splňují celý kontrakt)
v Pythonu dědičnost dodá jen formální aspekt (typová kontrola) nepřidá kontrolu kontraktu
A je odvozeno z B tak platí A je podtyp B resp. B je nadtyp A bázová třída = nadtřída odvozená třída = podtřída
odvození z abstraktní bázové třídy class MyContainer(collections.abc.Container): …
důvod je polymorfismus: využit je mechanismus předefinování/přidaní metod nepovinné! (duck polymorfismus)
mixiny v Pythonu lze dědit z vice tříd najednou (vícenásobná dědičnost)
dědíte ze dvou: základní třída (běžná třída s nějakým rozhraním, má datové členy) třída příměs: která dodává dodatečnou funkčnost (má jen jednu jedinou metodu)
objekty specializované třídy: mají nějakou funkčnost navíc specializované chování metod (musí splňovat kontrakt obecné třídy, ale mohou něco přidávat)
musí být vztah podtypu a nadtypu
dědičnost: je jeden z prostředků (možná nejlepší) pro implementaci specializace
bázová třída : odvozená třída obecná třída : specializovaná třída nadtřída (nadtyp) : podtřída (podtyp)
racionální čísla : celá čísla
class Rational: …
class Integer(Rational): …
existují specifické metody pouze pro Integer (ano, např. is_prime, modulo) bude potřeba něco (např. metody, číselné operace) předefinovat (ne) bude potřeba něco (např. atributy) přidat (ne, ale naopak v Integer je jeden navíc - jmenovatel je vždy 1) dědičnost v takovéto podobě není vhodná
Třída Syn dědí ze třídy Otec - je to správně? (není to správně) muselo by platit: syni jsou podmnozinou otců muselo by platit: každý syn je zároveň otcem muselo by platit: kde očekáváte otce, lze použít syna
Třída CerveneAuto dědí ze třídy Auto - je to správně? (není to správně) neplatí vztah specializace/generalizace není potřeba přidat nějaké metody není potřeba modifikovat metody nejsou potřeba nové atributy
Třída Pes dědí ze třídy Savec - je to správně? (není to správně) Třída Pes dědí ze třídy Zivocich - je to správně? (ano) Třída Hlodavec dědí ze třídy Zivocich a třída Kralik dědí ze třídy Hlodace - je to správně? (ano)
Třída Zakaznik dědí ze třídy Zamestnanec - je to správně (není to správně) zákazník nemá mzdu, pracovní dobu, …
Třída Zamestnanec i Zakaznik dedi ze třídy Osoba - je to správně (ne tak úplně) Osoba - identifikátor, datum narození, pohlaví, adresa nepotřebujeme znát o každém zákazníkovi všechny tyto informace