Minule jsme probraly třídy – jako příklad jsme si ukázaly třídu pro koťátka:
class Kotatko:
def __init__(self, jmeno):
self.jmeno = jmeno
def snez(self, jidlo):
print("{}: {} mi chutná!".format(self.jmeno, jidlo))
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
Zkus si udělat podobnou třídu pro štěňátka:
class Stenatko:
def __init__(self, jmeno):
self.jmeno = jmeno
def snez(self, jidlo):
print("{}: {} mi chutná!".format(self.jmeno, jidlo))
def zastekej(self):
print("{}: Haf!".format(self.jmeno))
Většina kódu je stejná! Kdybys měla napsat i třídu pro kuřátka, kůzlátka, slůňátka a háďátka, bez Ctrl+C by to bylo docela nudné. A protože jsou programátoři líní psát stejný kód několikrát (a hlavně ho potom udržovat), vymysleli mechanismus, jak se toho vyvarovat.
Koťátka i štěňátka jsou zvířátka. Můžeš si vytvořit třídu společnou pro všechna zvířátka a do ní napsat všechno, co je společné. Ve třídách pro jednotlivé druhy zvířat pak zbude jen to, co se liší. V Pythonu se to dělá takto:
class Zviratko:
def __init__(self, jmeno):
self.jmeno = jmeno
def snez(self, jidlo):
print("{}: {} mi chutná!".format(self.jmeno, jidlo))
class Kotatko(Zviratko):
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
class Stenatko(Zviratko):
def zastekej(self):
print("{}: Haf!".format(self.jmeno))
micka = Kotatko('Micka')
azorek = Stenatko('Azorek')
micka.zamnoukej()
azorek.zastekej()
micka.snez('myš')
azorek.snez('kost')
Jak to funguje?
Příkazem class Kotatko(Zviratko):
říkáš Pythonu, že třída Kotatko
dědí ze třídy Zviratko
(angl. inherits from Zviratko
).
Případně se můžeš setkat s jinými termíny:
„je odvozená” ze třídy Zviratko
,
(angl. derived from),
nebo ji “rozšiřuje” (angl. extends).
A když už jsme u terminologie, odvozeným třídám se
říká taky podtřídy (angl. subclasses)
a Zviratko
je tu nadtřída
(angl. superclass).
Když potom Python hledá nějakou metodu
(nebo jiný atribut), třeba micka.snez
,
a nenajde ji přímo ve třídě daného objektu (u nás
Kotatko
), podívá se do nadtřídy.
Takže všechno, co je definované pro
Zviratko
, platí i pro koťátka – dokud to výslovně nezměníš.
super()
Když se ti nebude líbit chování některé metody v nadtřídě, stačí dát metodu stejného jména do podtřídy:
class Kotatko(Zviratko):
def snez(self, jidlo):
print("{}: {} mi vůbec nechutná!".format(self.jmeno, jidlo))
micka = Kotatko('Micka')
micka.snez('granule')
Je to podobné jako když jsme minule přepisovaly
atribut pomocí micka.zamnoukej = 12345
.
Python atributy hledá napřed na samotném objektu,
potom na třídě toho objektu a pak na nadtřídě
(a případně dalších nadtřídách té nadtřídy).
Občas se může stát, že v takovéto přepsané metodě budeš
potřebovat použít původní funkčnost, jen budeš chtít udělat ještě něco navíc.
To umí zařídit speciální funkce super()
,
která umožňuje volat metody z nadtřídy.
Třeba takhle:
class Kotatko(Zviratko):
def snez(self, jidlo):
print("({} na {} chvíli fascinovaně kouká)".format(self.jmeno, jidlo))
super().snez(jidlo)
micka = Kotatko('Micka')
micka.snez('granule')
Pozor na to, že takhle volané metodě musíš dát všechny
argumenty, které potřebuje (kromě self
,
který se jako obvykle doplní automaticky).
Toho se dá i využít – můžeš použít i jiné argumenty
než dostala původní funkce:
class Hadatko(Zviratko):
def __init__(self, jmeno):
jmeno = jmeno.replace('s', 'sss')
jmeno = jmeno.replace('S', 'Sss')
super().__init__(jmeno)
standa = Hadatko('Stanislav')
standa.snez('myš')
Jak je vidět, super()
se dá bez problémů
kombinovat se speciálními metodami jako __init__
.
Dokonce se to dělá poměrně často!
Programátoři nezavedli dědičnost jen proto, že jsou
líní a nechtějí psát dvakrát stejný kód.
To je sice dobrý důvod, ale nadtřídy mají jednu
důležitější vlastnost. Když víš, že každé
Kotatko
nebo Stenatko
nebo jakákoli jiná podtřída je zvířátko,
můžeš si udělat seznam zvířátek s tím,
že pak bude jedno, jaká přesně zvířátka to jsou:
zviratka = [Kotatko('Micka'), Stenatko('Azorek')]
for zviratko in zviratka:
zviratko.snez('flákota')
Tohle je docela důležitá vlastnost podtříd:
když máš nějaké Kotatko
, můžeš ho použít
kdekoliv kde program očekává Zviratko
,
protože každé koťátko je zvířátko.
Tohle je docela dobrá pomůcka pro případy, kdy nebudeš vědět kterou třídu podědit z které. Každé koťátko nebo štěňátko je zvířátko, každá chata nebo panelák je stavení. V takových případech dává dědičnost smysl.
Někdy se ale stane, že tuhle pomůcku zkusíš použít a vyjde ti nesmysl jako „každé auto je volant”. V takovém případě dědičnost nepoužívej. I když jak auto tak volant se dají „otočit doprava”, u každého to znamená něco jiného – a určitě nejde auto použít kdekoli, kde bys chtěla použít volant. Takže v tomto případě je lepší si říct „každé auto má volant”, stejně jako „každé kotě má jméno”, udělat dvě nezávislé třídy a napsat něco jako:
class Auto:
def __init__(self):
self.volant = Volant()
(A až bude někdy nějaký vystudovaný informatik nespokojený s tím, že porušuješ Liskovové substituční princip, jde o právě tento problém.)
Když se teď podíváš na funkce zamnoukej
a zastekej
, možná tě napadne, že by se
daly pojmenovat lépe, aby se daly použít pro všechna
zvířata, podobně jako snez
.
Bude nejlepší je přejmenovat:
class Zviratko:
def __init__(self, jmeno):
self.jmeno = jmeno
def snez(self, jidlo):
print("{}: {} mi chutná!".format(self.jmeno, jidlo))
class Kotatko(Zviratko):
def udelej_zvuk(self):
print("{}: Mňau!".format(self.jmeno))
class Stenatko(Zviratko):
def udelej_zvuk(self):
print("{}: Haf!".format(self.jmeno))
zviratka = [Kotatko('Micka'), Stenatko('Azorek')]
for zviratko in zviratka:
zviratko.udelej_zvuk()
zviratko.snez('flákota')
Jak tenhle příklad naznačuje, psát nadtřídy, ze kterých se dobře dědí,
není jednoduché. Zvlášť to platí, kdyby se z nich mělo dědit v jiném
programu, než kde je nadtřída.
I z toho důvodu je dobré dědičnost používat hlavně v rámci svého kódu:
nedoporučuji dědit od tříd, které napsali ostatní (jako bool
nebo
pyglet.sprite.Sprite
), pokud autor nadtřídy výslovně nezmíní, že (a jak) se
z ní dědit má.
A to je zatím o třídách vše. Už toho víš dost na to, aby sis napsala vlastní zoo :)
{ "data": { "sessionMaterial": { "id": "session-material:2019/brno-podzim-pondeli:class:1", "title": "Dědičnost", "html": "\n \n \n\n <h1>Dědičnost</h1>\n<p>Minule jsme probraly třídy – jako příklad jsme si\nukázaly třídu pro koťátka:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n</pre></div><p>Zkus si udělat podobnou třídu pro štěňátka:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Stenatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">zastekej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Haf!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n</pre></div><p>Většina kódu je stejná!\nKdybys měla napsat i třídu pro kuřátka, kůzlátka,\nslůňátka a háďátka, bez Ctrl+C by to bylo docela nudné.\nA protože jsou programátoři líní psát stejný kód\nněkolikrát (a hlavně ho potom udržovat), vymysleli\nmechanismus, jak se toho vyvarovat.</p>\n<p>Koťátka i štěňátka jsou zvířátka.\nMůžeš si vytvořit třídu společnou pro všechna\nzvířátka a do ní napsat všechno, co je společné.\nVe třídách pro jednotlivé druhy zvířat pak zbude jen to, co se liší.\nV Pythonu se to dělá takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Zviratko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Stenatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">zastekej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Haf!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n\n<span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Micka'</span><span class=\"p\">)</span>\n<span class=\"n\">azorek</span> <span class=\"o\">=</span> <span class=\"n\">Stenatko</span><span class=\"p\">(</span><span class=\"s1\">'Azorek'</span><span class=\"p\">)</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n<span class=\"n\">azorek</span><span class=\"o\">.</span><span class=\"n\">zastekej</span><span class=\"p\">()</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'myš'</span><span class=\"p\">)</span>\n<span class=\"n\">azorek</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'kost'</span><span class=\"p\">)</span>\n</pre></div><p>Jak to funguje?\nPříkazem <code>class Kotatko(Zviratko):</code>\nříkáš Pythonu, že třída <code>Kotatko</code>\n<em>dědí</em> ze třídy <code>Zviratko</code>\n(angl. <em>inherits</em> from <code>Zviratko</code>).\nPřípadně se můžeš setkat s jinými termíny:\n„je odvozená” ze třídy <code>Zviratko</code>,\n(angl. <em>derived from</em>),\nnebo ji “rozšiřuje” (angl. <em>extends</em>).\nA když už jsme u terminologie, odvozeným třídám se\nříká taky <em>podtřídy</em> (angl. <em>subclasses</em>)\na <code>Zviratko</code> je tu <em>nadtřída</em>\n(angl. <em>superclass</em>).</p>\n<p>Když potom Python hledá nějakou metodu\n(nebo jiný atribut), třeba <code>micka.snez</code>,\na nenajde ji přímo ve třídě daného objektu (u nás\n<code>Kotatko</code>), podívá se do nadtřídy.\nTakže všechno, co je definované pro\n<code>Zviratko</code>, platí i pro koťátka – dokud to výslovně nezměníš.</p>\n<h2>Přepisování metod a <code>super()</code></h2>\n<p>Když se ti nebude líbit chování některé metody\nv nadtřídě, stačí dát metodu stejného jména do\npodtřídy:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: {} mi vůbec nechutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n\n<span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Micka'</span><span class=\"p\">)</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'granule'</span><span class=\"p\">)</span>\n</pre></div><div class=\"admonition python\"><p>Je to podobné jako když jsme minule přepisovaly\natribut pomocí <code>micka.zamnoukej = 12345</code>.\nPython atributy hledá napřed na samotném objektu,\npotom na třídě toho objektu a pak na nadtřídě\n(a případně dalších nadtřídách té nadtřídy).</p>\n</div><p>Občas se může stát, že v takovéto přepsané metodě budeš\npotřebovat použít původní funkčnost, jen budeš chtít udělat ještě něco navíc.\nTo umí zařídit speciální funkce <code>super()</code>,\nkterá umožňuje volat metody z nadtřídy.\nTřeba takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"({} na {} chvíli fascinovaně kouká)"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"n\">jidlo</span><span class=\"p\">)</span>\n\n\n<span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Micka'</span><span class=\"p\">)</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'granule'</span><span class=\"p\">)</span>\n</pre></div><p>Pozor na to, že takhle volané metodě musíš dát všechny\nargumenty, které potřebuje (kromě <code>self</code>,\nkterý se jako obvykle doplní automaticky).\nToho se dá i využít – můžeš použít i jiné argumenty\nnež dostala původní funkce:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Hadatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">'s'</span><span class=\"p\">,</span> <span class=\"s1\">'sss'</span><span class=\"p\">)</span>\n <span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">'S'</span><span class=\"p\">,</span> <span class=\"s1\">'Sss'</span><span class=\"p\">)</span>\n <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"n\">jmeno</span><span class=\"p\">)</span>\n\n\n<span class=\"n\">standa</span> <span class=\"o\">=</span> <span class=\"n\">Hadatko</span><span class=\"p\">(</span><span class=\"s1\">'Stanislav'</span><span class=\"p\">)</span>\n<span class=\"n\">standa</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'myš'</span><span class=\"p\">)</span>\n</pre></div><p>Jak je vidět, <code>super()</code> se dá bez problémů\nkombinovat se speciálními metodami jako <code>__init__</code>.\nDokonce se to dělá poměrně často!</p>\n<h2>Polymorfismus</h2>\n<p>Programátoři nezavedli dědičnost jen proto, že jsou\nlíní a nechtějí psát dvakrát stejný kód.\nTo je sice dobrý důvod, ale nadtřídy mají jednu\ndůležitější vlastnost. Když víš, že každé\n<code>Kotatko</code> nebo <code>Stenatko</code>\nnebo jakákoli jiná podtřída je zvířátko,\nmůžeš si udělat seznam zvířátek s tím,\nže pak bude jedno, jaká přesně zvířátka to jsou:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">zviratka</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Micka'</span><span class=\"p\">),</span> <span class=\"n\">Stenatko</span><span class=\"p\">(</span><span class=\"s1\">'Azorek'</span><span class=\"p\">)]</span>\n\n<span class=\"k\">for</span> <span class=\"n\">zviratko</span> <span class=\"ow\">in</span> <span class=\"n\">zviratka</span><span class=\"p\">:</span>\n <span class=\"n\">zviratko</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'flákota'</span><span class=\"p\">)</span>\n</pre></div><p>Tohle je docela důležitá vlastnost podtříd:\nkdyž máš nějaké <code>Kotatko</code>, můžeš ho použít\nkdekoliv kde program očekává <code>Zviratko</code>,\nprotože každé koťátko <em>je</em> zvířátko.</p>\n<div class=\"admonition note\"><p>Tohle je docela dobrá pomůcka pro případy, kdy nebudeš vědět\nkterou třídu podědit z které.\nKaždé <em>koťátko</em> nebo <em>štěňátko</em>\nje <em>zvířátko</em>, každá <em>chata</em>\nnebo <em>panelák</em> je <em>stavení</em>.\nV takových případech dává dědičnost smysl.</p>\n<p>Někdy se ale stane, že tuhle pomůcku zkusíš použít a vyjde ti\nnesmysl jako „každé auto je volant”.\nV takovém případě dědičnost nepoužívej.\nI když jak auto tak volant se dají „otočit doprava”,\nu každého to znamená něco jiného – a určitě nejde auto\npoužít kdekoli, kde bys chtěla použít volant.\nTakže v tomto případě je lepší si říct „každé auto\n<em>má</em> volant”, stejně jako „každé kotě\n<em>má</em> jméno”, udělat dvě nezávislé třídy a napsat něco jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Auto</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">volant</span> <span class=\"o\">=</span> <span class=\"n\">Volant</span><span class=\"p\">()</span>\n</pre></div><p>(A až bude někdy nějaký vystudovaný informatik nespokojený\ns tím, že porušuješ\n<a href=\"https://en.wikipedia.org/wiki/Liskov_substitution_principle\">Liskovové substituční princip</a>,\njde o právě tento problém.)</p>\n</div><h2>Generalizace</h2>\n<p>Když se teď podíváš na funkce <code>zamnoukej</code>\na <code>zastekej</code>, možná tě napadne, že by se\ndaly pojmenovat lépe, aby se daly použít pro všechna\nzvířata, podobně jako <code>snez</code>.\nBude nejlepší je přejmenovat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Zviratko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">udelej_zvuk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Stenatko</span><span class=\"p\">(</span><span class=\"n\">Zviratko</span><span class=\"p\">):</span>\n <span class=\"k\">def</span> <span class=\"nf\">udelej_zvuk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Haf!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n\n<span class=\"n\">zviratka</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Micka'</span><span class=\"p\">),</span> <span class=\"n\">Stenatko</span><span class=\"p\">(</span><span class=\"s1\">'Azorek'</span><span class=\"p\">)]</span>\n\n<span class=\"k\">for</span> <span class=\"n\">zviratko</span> <span class=\"ow\">in</span> <span class=\"n\">zviratka</span><span class=\"p\">:</span>\n <span class=\"n\">zviratko</span><span class=\"o\">.</span><span class=\"n\">udelej_zvuk</span><span class=\"p\">()</span>\n <span class=\"n\">zviratko</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'flákota'</span><span class=\"p\">)</span>\n</pre></div><p>Jak tenhle příklad naznačuje, psát nadtřídy, ze kterých se dobře dědí,\nnení jednoduché. Zvlášť to platí, kdyby se z nich mělo dědit v jiném\nprogramu, než kde je nadtřída.\nI z toho důvodu je dobré dědičnost používat hlavně v rámci svého kódu:\nnedoporučuji dědit od tříd, které napsali ostatní (jako <code>bool</code> nebo\n<code>pyglet.sprite.Sprite</code>), pokud autor nadtřídy výslovně nezmíní, že (a jak) se\nz ní dědit má.</p>\n<p>A to je zatím o třídách vše. Už toho víš dost na to,\naby sis napsala vlastní zoo :)</p>\n\n\n " } } }