← Přehled všech hodin

Dědičnost — bestiář na třídách

Cíl hodiny: Umíš vytvořit rodinu tříd, které sdílejí společný základ, a chápou, proč se stejná metoda může chovat jinak.
Jak stránku používat: vpravo nahoře je tlačítko Prezentace — schová všechno kromě jednoho bloku a přepíná se šipkami. U ukázek a cvičení je kód vlevo editovatelný: uprav ho a klikni na Spustit (nebo Ctrl+Enter), výsledek se objeví vpravo. Běží to přímo v prohlížeči, bez instalace.

1. Vysvětlení a souvislosti

Blok 1Problém, který dědičnost řeší1. Vysvětlení a souvislosti

Podívej se na tři třídy vedle sebe a zkus najít, co se opakuje:

Všechny umí to samé. Liší se jen v pár detailech. Kdybys chtěl přidat metodu uzdrav, musel bys ji napsat třikrát. A pak čtyřikrát. A pak…

Dědičnost znamená „tahle třída už umí všechno, co ten rodič, a navíc si přidá něco svého".

Blok 2Slovník pojmů1. Vysvětlení a souvislosti

Drž se jednoho názvosloví celý rok:

Termín Význam
rodičovská / základní třída ta obecná (Prisera)
odvozená / potomek ta konkrétní (Skret)
dědit automaticky převzít atributy a metody
přepsat metodu napsat vlastní verzi zděděné metody

Analogie, která funguje:

„Zvíře" je obecné. „Pes" je zvíře, které navíc štěká. Nemusíš psovi znovu vysvětlovat, že dýchá a jí — to má po zvířeti. Stačí dopsat to štěkání.

Blok 3Základní zápis1. Vysvětlení a souvislosti

Když metoda v potomkovi není, Python ji hledá u rodiče. Když tam je, použije tu z potomka. Tomu se říká přepsání metody.

Blok 4super() — zavolej rodiče1. Vysvětlení a souvislosti

Nejdůležitější technická věc hodiny:

class Drak(Prisera):
    def __init__(self, jmeno, zivoty, sila, barva):
        super().__init__(jmeno, zivoty, sila)   # ať to udělá rodič
        self.barva = barva                       # a tohle je navíc

super().__init__(...) znamená „rodiči, udělej svoji část". Pak si dopíšeš, co má tvoje třída navíc.

Kdybys to nezavolal, drak by neměl jméno ani životy — rodičův kód by se nespustil.

def utoc(self, cil):
    poskozeni = super().utoc(cil)     # udělej to, co dělá rodič
    return poskozeni * 2               # a ještě to zdvojnásob

super() funguje i v obyčejných metodách:

Blok 5Polymorfismus — nejkrásnější část1. Vysvětlení a souvislosti

Tady obvykle docvakne, k čemu to celé je:

bestiar = [Skret("Skřet", 30, 8), Vlk("Vlk", 20, 12), Drak("Drak", 200, 40, "rudý")]

for p in bestiar:
    st.write(p.zvuk())      # každá udělá SVOJI verzi

V seznamu jsou tři různé typy příšer. Voláš na nich stejnou metodu, ale každá se zachová po svém. Ty nemusíš vědět, která je která.

To je polymorfismus: „mnoho tvarů". Jedno volání, různé chování.

Tohle je zásadní, protože to výrazně zjednoduší tvůj kód.

Blok 6isinstance — zjištění typu1. Vysvětlení a souvislosti
isinstance(s, Skret)        # True
isinstance(s, Prisera)      # True - Skřet JE příšera
isinstance(s, Drak)         # False

Skřet je zároveň skřet i příšera. Potomek je vždycky i typem rodiče.

Používej střídmě — pokud kód potřebuje moc isinstance, měl by tam být polymorfismus.

Blok 7Kdy dědit a kdy ne1. Vysvětlení a souvislosti

Zapamatuj si jednoduché pravidlo:

Dědičnost použij, když platí věta „X JE Y". Skřet je příšera. ✅ Meč je předmět. ✅ Hrdina inventář — to není dědičnost, to je atribut. ❌

Špatné použití dědičnosti dělá kód horším, ne lepším.

Blok 8Praktický návrh bestiáře1. Vysvětlení a souvislosti

Všimni si, že konkrétní příšery mají __init__ bez parametrů. Samy vědí, jaké mají hodnoty. Vytvoříš je jednoduše: Skret().

Poznámky pro učiteleTechnické pozadí pro učitele1. Vysvětlení a souvislosti
  • Python podporuje vícenásobnou dědičnost a řeší ji přes MRO (C3 linearizace). Do výuky nepatří, ale vy o tom vědět máte, kdyby se někdo zeptal.
  • Abstraktní třídy: modul abc, dekorátor @abstractmethod. Pro pokročilé žáky je to hezké rozšíření (příšera, kterou nelze vytvořit přímo).
  • super() v Pythonu 3 nepotřebuje argumenty. Starý zápis super(Skret, self) uvidí děti ve starých návodech na internetu.
  • Pro C# programátora: class Skret(Prisera) je class Skret : Prisera, super().__init__() je : base(...). Rozdíl: v Pythonu jsou všechny metody virtuální, override se nepíše.
  • Kompozice je často lepší než dědičnost. Doporučená věta: „Dědi jen tehdy, když potomek skutečně může nahradit rodiče."
Blok 9Časté chyby1. Vysvětlení a souvislosti
Chyba Příčina Řešení
AttributeError: no attribute 'jmeno' Chybí super().__init__() Zavolat na začátku __init__
TypeError: __init__ takes 1 argument Špatný počet argumentů u super() Zkontrolovat rodičovskou hlavičku
Přepsaná metoda se nevolá Překlep v názvu metody Musí být přesně stejný název
Sdílený seznam mezi objekty Seznam v těle třídy místo v __init__ Vytvářet v __init__
NameError: Prisera is not defined Rodič definovaný až po potomkovi Rodiče psát nahoru
Dědičnost tam, kde má být atribut „má" místo „je" Použít kompozici

2. Ukázky pro projekci

Blok 10Ukázka 1 — Opakování versus dědičnost2. Ukázky pro projekci
demo/demo1_proc_dedicnost.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 11Ukázka 2 — super() krok za krokem2. Ukázky pro projekci
demo/demo2_super.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 12Ukázka 3 — Bestiář s vlastními schopnostmi2. Ukázky pro projekci
demo/demo3_bestiar_tridy.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

3. Cvičení na hodinu

Blok 13Cvičení 1 — Rodina příšer (15 min)3. Cvičení na hodinu

Zadání:

  1. Napiš rodičovskou třídu Prisera se jménem, životy, silou a emoji
  2. Přidej metodu zvuk(self) vracející "..."
  3. Vytvoř tři potomky: Skret, Vlk, Kostlivec
  4. V každém potomkovi zavolej super().__init__(...) s vlastními hodnotami
  5. Přepiš zvuk() v každém potomkovi a vypiš je cyklem
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + přidat čtvrtou příšeru bez úpravy zbytku kódu
cviceni/cviceni1_rodina.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Na co si dát pozor

Očekávaný výsledek: tři příšery, každá vydává jiný zvuk.

Řešení 1 — jedna z možných variant
reseni/reseni1_rodina.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 14Cvičení 2 — Speciální schopnosti (20 min)3. Cvičení na hodinu

Zadání:

  1. Přidej rodiči metodu utoc(self) vracející sila + hod kostkou
  2. Ve třídě Vlk přepiš utoc tak, aby útočil dvakrát
  3. Ve třídě Kostlivec přepiš prijmi_poskozeni na poloviční poškození
  4. Použij v přepsaných metodách super(), ne kopírování kódu
  5. Otestuj: nech každou příšeru desetkrát zaútočit a vypiš průměr
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + přidat draka s 30% šancí na trojnásobný útok
cviceni/cviceni2_schopnosti.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Na co si dát pozor

Očekávaný výsledek: čísla ukazují, že schopnosti opravdu fungují.

Řešení 2 — jedna z možných variant
reseni/reseni2_schopnosti.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 15Cvičení 3 — Typy hrdinů (20 min)3. Cvičení na hodinu

Zadání:

  1. Napiš rodiče Hrdina s životy, silou, magií a metodou utoc()
  2. Vytvoř Bojovnik, který má víc životů a útočí silou
  3. Vytvoř Kouzelnik, který má míň životů a útočí magií
  4. Vytvoř Lupic, který má 25% šanci na dvojnásobné poškození
  5. Nech uživatele vybrat typ hrdiny a vytvoř odpovídající objekt
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + porovnat všechny tři v tabulce
cviceni/cviceni3_hrdinove.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Na co si dát pozor

Očekávaný výsledek: výběr povolání vytvoří objekt s jiným chováním.

Řešení 3 — jedna z možných variant
reseni/reseni3_hrdinove.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 16Cvičení 4 — Souboj napříč třídami (20 min)3. Cvičení na hodinu

Zadání:

  1. Nech uživatele vybrat typ hrdiny a typ příšery
  2. Vytvoř oba objekty a ulož je do session_state
  3. Tlačítkem proveď kolo souboje — obě strany zaútočí svou metodou
  4. Do logu zapisuj popisy útoků, které metody vracejí
  5. Po vítězství přidej hrdinovi zlato příšery
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + statistika, kolik kol souboj trval
cviceni/cviceni4_souboj_typu.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Na co si dát pozor

Očekávaný výsledek: libovolná kombinace hrdiny a příšery funguje.

Řešení 4 — jedna z možných variant
reseni/reseni4_souboj_typu.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 17Cvičení 5 — PyQuest: bestiář a povolání (25 min)3. Cvičení na hodinu

Zadání:

  1. Převeď hrdinu na rodiče Hrdina a přidej tři povolání jako potomky
  2. Vytvoř bestiář jako seznam tříd příšer
  3. Při výpravě náhodně vyber příšeru a proveď souboj
  4. Výsledek souboje zapiš do deníku včetně typu příšery
  5. Zobraz v postranním panelu typ hrdiny a jeho zvláštní schopnost
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + přidat bosse, který se objeví po deseti výpravách
cviceni/cviceni5_pyquest_bestiar.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Na co si dát pozor

Očekávaný výsledek: hra s výběrem povolání a různorodými nepřáteli.


Řešení 5 — jedna z možných variant
reseni/reseni5_pyquest_bestiar.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.


4. Domácí úkol

Blok 18Domácí úkol na příští hodinu4. Domácí úkol

Přidej do bestiáře vlastní příšeru s nějakou zvláštní schopností, kterou vytvoříš přepsáním metody. Například příšera, která se po každém kole trochu uzdraví, nebo která má šanci útok úplně minout. Napiš do komentáře, kterou metodu jsi přepsal a proč.

Zobrazit ukázkové řešení domácího úkolu

Toto je jedna z možných variant, jak mohl úkol dopadnout. Tvoje řešení se může lišit a to je v pořádku.

domaci/domaci_ukol14.py
Tady se objeví výsledekKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 19Oficiální dokumentace4. Domácí úkol

Oficiální dokumentace se hodí, když si chceš ověřit, jak Python dědí třídy, jak funguje super() nebo kdy použít isinstance(). Je v angličtině, ale i krátké ukázky a názvy metod ti často rychle napoví.

Co jsme použili Oficiální dokumentace Co tam najdeš
třídy a objekty Classes základ práce s třídami, metodami a instancemi
dědičnost Inheritance jak odvozovat třídy a přepisovat jejich chování
super() super zavolání rodičovského konstruktoru nebo metody
isinstance() isinstance ověření, jestli objekt patří do dané třídy
přepsání metod A First Look at Classes jak třídy skládají data a chování do společného základu

5. Umíme informatiku

Cvičení Odkaz Proč se hodí
Kódování a modelování umimeinformatiku.cz Hierarchie a klasifikace
Algoritmické myšlení umimeinformatiku.cz Zobecňování
Programování v Pythonu umimeinformatiku.cz Struktura kódu
Týmovka umimeinformatiku.cz Společné řešení problému