Dědičnost

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íš.

Přepisování metod a 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!

Polymorfismus

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 volant”, stejně jako „každé kotě 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.)

Generalizace

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&#x11B;di&#x10D;nost</h1>\n<p>Minule jsme probraly t&#x159;&#xED;dy &#x2013; jako p&#x159;&#xED;klad jsme si\nuk&#xE1;zaly t&#x159;&#xED;du pro ko&#x165;&#xE1;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\">&quot;{}: {} mi chutn&#xE1;!&quot;</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\">&quot;{}: M&#x148;au!&quot;</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&#x11B;lat podobnou t&#x159;&#xED;du pro &#x161;t&#x11B;&#x148;&#xE1;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\">&quot;{}: {} mi chutn&#xE1;!&quot;</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\">&quot;{}: Haf!&quot;</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&#x11B;t&#x161;ina k&#xF3;du je stejn&#xE1;!\nKdybys m&#x11B;la napsat i t&#x159;&#xED;du pro ku&#x159;&#xE1;tka, k&#x16F;zl&#xE1;tka,\nsl&#x16F;&#x148;&#xE1;tka a h&#xE1;&#x10F;&#xE1;tka, bez Ctrl+C by to bylo docela nudn&#xE9;.\nA proto&#x17E;e jsou program&#xE1;to&#x159;i l&#xED;n&#xED; ps&#xE1;t stejn&#xFD; k&#xF3;d\nn&#x11B;kolikr&#xE1;t (a hlavn&#x11B; ho potom udr&#x17E;ovat), vymysleli\nmechanismus, jak se toho vyvarovat.</p>\n<p>Ko&#x165;&#xE1;tka i &#x161;t&#x11B;&#x148;&#xE1;tka jsou zv&#xED;&#x159;&#xE1;tka.\nM&#x16F;&#x17E;e&#x161; si vytvo&#x159;it t&#x159;&#xED;du spole&#x10D;nou pro v&#x161;echna\nzv&#xED;&#x159;&#xE1;tka a do n&#xED; napsat v&#x161;echno, co je spole&#x10D;n&#xE9;.\nVe t&#x159;&#xED;d&#xE1;ch pro jednotliv&#xE9; druhy zv&#xED;&#x159;at pak zbude jen to, co se li&#x161;&#xED;.\nV&#xA0;Pythonu se to d&#x11B;l&#xE1; 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\">&quot;{}: {} mi chutn&#xE1;!&quot;</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\">&quot;{}: M&#x148;au!&quot;</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\">&quot;{}: Haf!&quot;</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\">&apos;Micka&apos;</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\">&apos;Azorek&apos;</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\">&apos;my&#x161;&apos;</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\">&apos;kost&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Jak to funguje?\nP&#x159;&#xED;kazem <code>class Kotatko(Zviratko):</code>\n&#x159;&#xED;k&#xE1;&#x161; Pythonu, &#x17E;e t&#x159;&#xED;da <code>Kotatko</code>\n<em>d&#x11B;d&#xED;</em> ze t&#x159;&#xED;dy <code>Zviratko</code>\n(angl. <em>inherits</em> from <code>Zviratko</code>).\nP&#x159;&#xED;padn&#x11B; se m&#x16F;&#x17E;e&#x161; setkat s&#xA0;jin&#xFD;mi term&#xED;ny:\n&#x201E;je odvozen&#xE1;&#x201D; ze t&#x159;&#xED;dy <code>Zviratko</code>,\n(angl. <em>derived from</em>),\nnebo ji &#x201C;roz&#x161;i&#x159;uje&#x201D; (angl. <em>extends</em>).\nA kdy&#x17E; u&#x17E; jsme u terminologie, odvozen&#xFD;m t&#x159;&#xED;d&#xE1;m se\n&#x159;&#xED;k&#xE1; taky <em>podt&#x159;&#xED;dy</em> (angl. <em>subclasses</em>)\na <code>Zviratko</code> je tu <em>nadt&#x159;&#xED;da</em>\n(angl. <em>superclass</em>).</p>\n<p>Kdy&#x17E; potom Python hled&#xE1; n&#x11B;jakou metodu\n(nebo jin&#xFD; atribut), t&#x159;eba <code>micka.snez</code>,\na nenajde ji p&#x159;&#xED;mo ve t&#x159;&#xED;d&#x11B; dan&#xE9;ho objektu (u n&#xE1;s\n<code>Kotatko</code>), pod&#xED;v&#xE1; se do nadt&#x159;&#xED;dy.\nTak&#x17E;e v&#x161;echno, co je definovan&#xE9; pro\n<code>Zviratko</code>, plat&#xED; i pro ko&#x165;&#xE1;tka &#x2013; dokud to v&#xFD;slovn&#x11B; nezm&#x11B;n&#xED;&#x161;.</p>\n<h2>P&#x159;episov&#xE1;n&#xED; metod a <code>super()</code></h2>\n<p>Kdy&#x17E; se ti nebude l&#xED;bit chov&#xE1;n&#xED; n&#x11B;kter&#xE9; metody\nv nadt&#x159;&#xED;d&#x11B;, sta&#x10D;&#xED; d&#xE1;t metodu stejn&#xE9;ho jm&#xE9;na do\npodt&#x159;&#xED;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\">&quot;{}: {} mi v&#x16F;bec nechutn&#xE1;!&quot;</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\">&apos;Micka&apos;</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\">&apos;granule&apos;</span><span class=\"p\">)</span>\n</pre></div><div class=\"admonition python\"><p>Je to podobn&#xE9; jako kdy&#x17E; jsme minule p&#x159;episovaly\natribut pomoc&#xED; <code>micka.zamnoukej = 12345</code>.\nPython atributy hled&#xE1; nap&#x159;ed na samotn&#xE9;m objektu,\npotom na t&#x159;&#xED;d&#x11B; toho objektu a pak na nadt&#x159;&#xED;d&#x11B;\n(a p&#x159;&#xED;padn&#x11B; dal&#x161;&#xED;ch nadt&#x159;&#xED;d&#xE1;ch t&#xE9; nadt&#x159;&#xED;dy).</p>\n</div><p>Ob&#x10D;as se m&#x16F;&#x17E;e st&#xE1;t, &#x17E;e v takov&#xE9;to p&#x159;epsan&#xE9; metod&#x11B; bude&#x161;\npot&#x159;ebovat pou&#x17E;&#xED;t p&#x16F;vodn&#xED; funk&#x10D;nost, jen bude&#x161; cht&#xED;t ud&#x11B;lat je&#x161;t&#x11B; n&#x11B;co nav&#xED;c.\nTo um&#xED; za&#x159;&#xED;dit speci&#xE1;ln&#xED; funkce <code>super()</code>,\nkter&#xE1; umo&#x17E;&#x148;uje volat metody z nadt&#x159;&#xED;dy.\nT&#x159;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\">&quot;({} na {} chv&#xED;li fascinovan&#x11B; kouk&#xE1;)&quot;</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\">&apos;Micka&apos;</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\">&apos;granule&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Pozor na to, &#x17E;e takhle volan&#xE9; metod&#x11B; mus&#xED;&#x161; d&#xE1;t v&#x161;echny\nargumenty, kter&#xE9; pot&#x159;ebuje (krom&#x11B; <code>self</code>,\nkter&#xFD; se jako obvykle dopln&#xED; automaticky).\nToho se d&#xE1; i vyu&#x17E;&#xED;t &#x2013; m&#x16F;&#x17E;e&#x161; pou&#x17E;&#xED;t i jin&#xE9; argumenty\nne&#x17E; dostala p&#x16F;vodn&#xED; 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\">&apos;s&apos;</span><span class=\"p\">,</span> <span class=\"s1\">&apos;sss&apos;</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\">&apos;S&apos;</span><span class=\"p\">,</span> <span class=\"s1\">&apos;Sss&apos;</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\">&apos;Stanislav&apos;</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\">&apos;my&#x161;&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Jak je vid&#x11B;t, <code>super()</code> se d&#xE1; bez probl&#xE9;m&#x16F;\nkombinovat se speci&#xE1;ln&#xED;mi metodami jako <code>__init__</code>.\nDokonce se to d&#x11B;l&#xE1; pom&#x11B;rn&#x11B; &#x10D;asto!</p>\n<h2>Polymorfismus</h2>\n<p>Program&#xE1;to&#x159;i nezavedli d&#x11B;di&#x10D;nost jen proto, &#x17E;e jsou\nl&#xED;n&#xED; a necht&#x11B;j&#xED; ps&#xE1;t dvakr&#xE1;t stejn&#xFD; k&#xF3;d.\nTo je sice dobr&#xFD; d&#x16F;vod, ale nadt&#x159;&#xED;dy maj&#xED; jednu\nd&#x16F;le&#x17E;it&#x11B;j&#x161;&#xED; vlastnost. Kdy&#x17E; v&#xED;&#x161;, &#x17E;e ka&#x17E;d&#xE9;\n<code>Kotatko</code> nebo <code>Stenatko</code>\nnebo jak&#xE1;koli jin&#xE1; podt&#x159;&#xED;da je zv&#xED;&#x159;&#xE1;tko,\nm&#x16F;&#x17E;e&#x161; si ud&#x11B;lat seznam zv&#xED;&#x159;&#xE1;tek s t&#xED;m,\n&#x17E;e pak bude jedno, jak&#xE1; p&#x159;esn&#x11B; zv&#xED;&#x159;&#xE1;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\">&apos;Micka&apos;</span><span class=\"p\">),</span> <span class=\"n\">Stenatko</span><span class=\"p\">(</span><span class=\"s1\">&apos;Azorek&apos;</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\">&apos;fl&#xE1;kota&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Tohle je docela d&#x16F;le&#x17E;it&#xE1; vlastnost podt&#x159;&#xED;d:\nkdy&#x17E; m&#xE1;&#x161; n&#x11B;jak&#xE9; <code>Kotatko</code>, m&#x16F;&#x17E;e&#x161; ho pou&#x17E;&#xED;t\nkdekoliv kde program o&#x10D;ek&#xE1;v&#xE1; <code>Zviratko</code>,\nproto&#x17E;e ka&#x17E;d&#xE9; ko&#x165;&#xE1;tko <em>je</em> zv&#xED;&#x159;&#xE1;tko.</p>\n<div class=\"admonition note\"><p>Tohle je docela dobr&#xE1; pom&#x16F;cka pro p&#x159;&#xED;pady, kdy nebude&#x161; v&#x11B;d&#x11B;t\nkterou t&#x159;&#xED;du pod&#x11B;dit z kter&#xE9;.\nKa&#x17E;d&#xE9; <em>ko&#x165;&#xE1;tko</em> nebo <em>&#x161;t&#x11B;&#x148;&#xE1;tko</em>\nje <em>zv&#xED;&#x159;&#xE1;tko</em>, ka&#x17E;d&#xE1; <em>chata</em>\nnebo <em>panel&#xE1;k</em> je <em>staven&#xED;</em>.\nV takov&#xFD;ch p&#x159;&#xED;padech d&#xE1;v&#xE1; d&#x11B;di&#x10D;nost smysl.</p>\n<p>N&#x11B;kdy se ale stane, &#x17E;e tuhle pom&#x16F;cku zkus&#xED;&#x161; pou&#x17E;&#xED;t a vyjde ti\nnesmysl jako &#x201E;ka&#x17E;d&#xE9; auto je volant&#x201D;.\nV takov&#xE9;m p&#x159;&#xED;pad&#x11B; d&#x11B;di&#x10D;nost nepou&#x17E;&#xED;vej.\nI kdy&#x17E; jak auto tak volant se daj&#xED; &#x201E;oto&#x10D;it doprava&#x201D;,\nu ka&#x17E;d&#xE9;ho to znamen&#xE1; n&#x11B;co jin&#xE9;ho &#x2013; a ur&#x10D;it&#x11B; nejde auto\npou&#x17E;&#xED;t kdekoli, kde bys cht&#x11B;la pou&#x17E;&#xED;t volant.\nTak&#x17E;e v tomto p&#x159;&#xED;pad&#x11B; je lep&#x161;&#xED; si &#x159;&#xED;ct &#x201E;ka&#x17E;d&#xE9; auto\n<em>m&#xE1;</em> volant&#x201D;, stejn&#x11B; jako &#x201E;ka&#x17E;d&#xE9; kot&#x11B;\n<em>m&#xE1;</em> jm&#xE9;no&#x201D;, ud&#x11B;lat dv&#x11B; nez&#xE1;visl&#xE9; t&#x159;&#xED;dy a napsat n&#x11B;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&#x17E; bude n&#x11B;kdy n&#x11B;jak&#xFD; vystudovan&#xFD; informatik nespokojen&#xFD;\ns t&#xED;m, &#x17E;e poru&#x161;uje&#x161;\n<a href=\"https://en.wikipedia.org/wiki/Liskov_substitution_principle\">Liskovov&#xE9; substitu&#x10D;n&#xED; princip</a>,\njde o pr&#xE1;v&#x11B; tento probl&#xE9;m.)</p>\n</div><h2>Generalizace</h2>\n<p>Kdy&#x17E; se te&#x10F; pod&#xED;v&#xE1;&#x161; na funkce <code>zamnoukej</code>\na <code>zastekej</code>, mo&#x17E;n&#xE1; t&#x11B; napadne, &#x17E;e by se\ndaly pojmenovat l&#xE9;pe, aby se daly pou&#x17E;&#xED;t pro v&#x161;echna\nzv&#xED;&#x159;ata, podobn&#x11B; jako <code>snez</code>.\nBude nejlep&#x161;&#xED; je p&#x159;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\">&quot;{}: {} mi chutn&#xE1;!&quot;</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\">&quot;{}: M&#x148;au!&quot;</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\">&quot;{}: Haf!&quot;</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\">&apos;Micka&apos;</span><span class=\"p\">),</span> <span class=\"n\">Stenatko</span><span class=\"p\">(</span><span class=\"s1\">&apos;Azorek&apos;</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\">&apos;fl&#xE1;kota&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Jak tenhle p&#x159;&#xED;klad nazna&#x10D;uje, ps&#xE1;t nadt&#x159;&#xED;dy, ze kter&#xFD;ch se dob&#x159;e d&#x11B;d&#xED;,\nnen&#xED; jednoduch&#xE9;. Zvl&#xE1;&#x161;&#x165; to plat&#xED;, kdyby se z&#xA0;nich m&#x11B;lo d&#x11B;dit v&#xA0;jin&#xE9;m\nprogramu, ne&#x17E; kde je nadt&#x159;&#xED;da.\nI z&#xA0;toho d&#x16F;vodu je dobr&#xE9; d&#x11B;di&#x10D;nost pou&#x17E;&#xED;vat hlavn&#x11B; v r&#xE1;mci sv&#xE9;ho k&#xF3;du:\nnedoporu&#x10D;uji d&#x11B;dit od t&#x159;&#xED;d, kter&#xE9; napsali ostatn&#xED; (jako <code>bool</code> nebo\n<code>pyglet.sprite.Sprite</code>), pokud autor nadt&#x159;&#xED;dy v&#xFD;slovn&#x11B; nezm&#xED;n&#xED;, &#x17E;e (a jak) se\nz&#xA0;n&#xED; d&#x11B;dit m&#xE1;.</p>\n<p>A to je zat&#xED;m o t&#x159;&#xED;d&#xE1;ch v&#x161;e. U&#x17E; toho v&#xED;&#x161; dost na to,\naby sis napsala vlastn&#xED; zoo :)</p>\n\n\n        "
    }
  }
}