← Přehled všech hodin

Úklid kódu — moduly, importy a vlastní knihovna

Cíl hodiny: Umíš rozdělit velký soubor do několika menších, importovat vlastní moduly a ukládat objekty do JSON.
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

Poznámky pro učiteleMotivace — otevřete jejich vlastní soubor1. Vysvětlení a souvislosti

Nejlepší úvod je ukázat jejich app.py z minulé hodiny:

Kolik má tenhle soubor řádků? Tři sta? Čtyři sta? Zkus najít třídu Drak. Kolikrát jsi musel rolovat?

A teď si představ, že jich tam bude tisíc. Takhle vypadá každý program, který někdo skutečně používá. Proto se kód rozděluje do souborů.

Klíčová věta hodiny:

Dnes nepřidáme ani jednu novou funkci. Program bude po hodině dělat přesně to samé. Ale bude se v něm dát žít.

To je důležité říct nahlas — děti jinak mají pocit, že se nic nestalo. Pojmenujte to: refaktoring = zlepšení struktury bez změny chování.

Blok 1Co je modul1. Vysvětlení a souvislosti
pyquest/
├── app.py          ← spouští se
├── data.py         ← místa, předměty, ceny
├── postavy.py      ← třídy Hrdina, Prisera...
└── ulozeni.py      ← načítání a ukládání

Modul je prostě soubor s Pythonem. Nic víc. Když napíšeš postavy.py, máš modul jménem postavy.

Blok 2Tři způsoby importu1. Vysvětlení a souvislosti
import data                       # 1
st.write(data.MISTA)

from data import MISTA            # 2
st.write(MISTA)

from postavy import Hrdina, Drak  # 3
Zápis Kdy použít
import data Je vidět, odkud věc pochází. Bezpečné.
from data import MISTA Krátké, když z modulu bereš pár věcí.
from data import * Nikdy. Nevidíš, co se přineslo.

Doporučení: varianta 3 pro třídy a funkce, varianta 1 pro data.

Blok 3Jak Python hledá moduly1. Vysvětlení a souvislosti

Tohle vysvětlete, jinak budou zmatení z chyb:

Když napíšeš import postavy, Python se podívá: 1. do složky, kde je spouštěný soubor, 2. do nainstalovaných balíčků.

Proto musí být postavy.py ve stejné složce jako app.py.

Chyba ModuleNotFoundError: No module named 'postavy' má skoro vždy jednu ze tří příčin: špatná složka, překlep v názvu, nebo koncovka .py v importu.

Blok 4Pozor na kruhový import1. Vysvětlení a souvislosti
# postavy.py
from ulozeni import nacti     # ← ulozeni importuje postavy

# ulozeni.py
from postavy import Hrdina    # ← postavy importuje ulozeni

Dva soubory na sebe čekají navzájem. Python to vzdá a zahlásí chybu. Pravidlo: udělej si směr. Data neví o postavách. Postavy neví o aplikaci. Aplikace ví o všech.

data.py     (neimportuje nic vlastního)
   ↑
postavy.py  (může importovat data)
   ↑
ulozeni.py  (může importovat postavy)
   ↑
app.py      (importuje všechno)

Nakreslete tuhle šipku na tabuli. Řeší to 90 % problémů.

Blok 5Zrádnost: kód v modulu se spustí1. Vysvětlení a souvislosti

Řešení, které uvidíš v každém tutoriálu:

__name__ je proměnná, kterou Python nastaví sám. Když soubor spouštíš, je v ní "__main__". Když ho importuješ, je v ní jméno modulu.

Použití: jednoduché testy modulu na jeho konci.

Blok 6Serializace objektů — to_dict a from_dict1. Vysvětlení a souvislosti

Objekty se do JSON uložit nedají. Podívej se:

json.dumps(hrdina)     # TypeError: Object of type Hrdina is not JSON serializable

JSON umí jen slovníky, seznamy, čísla, texty a True/False/None. Objekt tam prostě nepatří. Musíš mu vysvětlit, jak se má „složit do krabice".

class Hrdina:
    def to_dict(self):
        """Objekt → slovník (do souboru)."""
        return {
            "jmeno": self.jmeno,
            "zivoty": self.zivoty,
            "zlato": self.zlato,
            "typ": type(self).__name__,
        }

    @staticmethod
    def from_dict(d):
        """Slovník → objekt (ze souboru)."""
        h = Hrdina(d["jmeno"])
        h.zivoty = d["zivoty"]
        h.zlato = d["zlato"]
        return h

Analogie: „skládám nábytek do krabice a zase ho složím zpátky". Klíč "typ" je důležitý — bez něj po načtení nepoznáš, jestli to byl bojovník nebo kouzelník.

Poznámky pro učiteleTechnické pozadí pro učitele1. Vysvětlení a souvislosti
  • import modul spustí jednou a uloží do sys.modules. Opakovaný import už nic nedělá. Proto Streamlit hot-reload někdy nezachytí změnu v modulu — řešení je restart, případně importlib.reload.
  • Balíček = složka s __init__.py. Do výuky pro 12–15 let bych to nedával, ploché soubory stačí a __init__.py je od Pythonu 3.3 nepovinný (namespace packages).
  • Pro C# programátora: modul je zhruba jako soubor s třídou, import je using, ale importuje se soubor, ne namespace. Neexistuje internal/private na úrovni modulu, jen konvence _nazev = „nesahej na to".
  • Skutečná serializace v produkci: dataclasses.asdict, pydantic, attrs. to_dict/from_dict je ale pedagogicky nejlepší — děti vidí, co se děje.
  • @staticmethod vs @classmethod: pro from_dict je čistší @classmethod (pracuje s cls), ale @staticmethod je pro děti srozumitelnější.
Poznámky pro učitelePostup refaktoringu na hodině1. Vysvětlení a souvislosti

Nedělejte to najednou. Postupujte v tomto pořadí a po každém kroku spusťte aplikaci:

  1. Vyjmi data (konstanty, slovníky) → data.py, přidej import, spusť.
  2. Vyjmi třídypostavy.py, přidej import, spusť.
  3. Vyjmi ukládáníulozeni.py, přidej import, spusť.
  4. V app.py zůstane jen UI.

Po každém kroku spusť aplikaci. Když nefunguje, víš přesně, co jsi rozbil. Když přesuneš všechno najednou a spadne to, hledáš chybu půl hodiny.

Tohle je nejcennější návyk celé hodiny.

Blok 7Časté chyby1. Vysvětlení a souvislosti
Chyba Příčina Řešení
ModuleNotFoundError Soubor v jiné složce nebo překlep Stejná složka, přesný název
import postavy.py Koncovka v importu Bez .py
ImportError: cannot import name Kruhový import Dodržet směr šipky
NameError po přesunu Zapomenutý import v novém modulu Doplnit import random apod.
Změna v modulu se neprojeví Cache importů Restartovat aplikaci
Object is not JSON serializable Ukládá se objekt Použít to_dict()
Po načtení je hrdina špatného typu Chybí klíč "typ" Uložit a přečíst typ

2. Ukázky pro projekci

Blok 8Ukázka 1 — Jeden soubor versus víc souborů2. Ukázky pro projekci
demo/demo1_proc_moduly.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 9Ukázka 2 — Tři způsoby importu2. Ukázky pro projekci
demo/demo2_zpusoby_importu.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 10Ukázka 3 — to_dict a from_dict2. Ukázky pro projekci
demo/demo3_serializace.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 11Cvičení 1 — První modul (15 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř soubor data.py a dej do něj slovník MISTA
  2. Přidej do něj i PREDMETY a CENY
  3. V app.py napiš import data
  4. Vypiš místa přes data.MISTA
  5. Přidej do data.py nové místo a ověř, že se v aplikaci objeví
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + vyzkoušet i from data import MISTA
cviceni/cviceni1_prvni_modul.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: aplikace čte data z jiného souboru.

Řešení 1 — jedna z možných variant
reseni/reseni1_prvni_modul.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 12Cvičení 2 — Modul s funkcemi (20 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř nastroje.py s funkcí hod_kostkou(pocet, stran)
  2. Přidej funkci procenta(cast, celek) vracející text jako "75 %"
  3. Přidej funkci zdravi_bar(zivoty, max_zivoty) vracející "█████░░░░░"
  4. Na konec nastroje.py přidej if __name__ == "__main__": s testem
  5. Použij všechny tři funkce v aplikaci
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Bod 3
Výzva Body 4–5
cviceni/cviceni2_modul_funkci.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: vlastní mini-knihovna, kterou lze používat kdekoli.

Řešení 2 — jedna z možných variant
reseni/reseni2_modul_funkci.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 13Cvičení 3 — Třídy do vlastního modulu (20 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř postavy.py a přesuň do něj třídu Bojujici
  2. Přesuň i Hrdina, Bojovnik, Kouzelnik, Lupic
  3. Přesuň příšery — Prisera, Skret, Vlk, Drak
  4. Nezapomeň na import random uvnitř postavy.py
  5. V aplikaci naimportuj jen to, co potřebuješ
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + slovník POVOLANI přímo v postavy.py
cviceni/cviceni3_tridy_modul.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: app.py je najednou o dvě stě řádků kratší.

Řešení 3 — jedna z možných variant
reseni/reseni3_tridy_modul.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í 4 — Ukládání objektů (20 min)3. Cvičení na hodinu

Zadání:

  1. Přidej třídě Hrdina metodu to_dict()
  2. Přidej statickou metodu from_dict(d)
  3. Do slovníku ulož i klíč "typ" s názvem třídy
  4. Vytvoř ulozeni.py s funkcemi uloz(hrdina) a nacti()
  5. Otestuj: ulož hrdinu, restartuj aplikaci, načti ho zpět
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + ať from_dict vrátí správné povolání podle "typ"
cviceni/cviceni4_ukladani_objektu.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: hrdina přežije restart aplikace i s povoláním.

Řešení 4 — jedna z možných variant
reseni/reseni4_ukladani_objektu.py
Tenhle kód potřebuje ukládat soubory, což v prohlížeči nejde — spusť ho na počítači příkazem streamlit run.
Blok 15Cvičení 5 — PyQuest: velký úklid (25 min)3. Cvičení na hodinu

Zadání:

  1. Rozděl hru na data.py, postavy.py, ulozeni.py a app.py
  2. Po každém přesunu aplikaci spusť a ověř, že funguje
  3. Dodrž směr importů — data neví o postavách
  4. V app.py nech jen UI, žádné třídy ani data
  5. Přidej do každého modulu docstring, co v něm je
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 + přidat nastroje.py s pomocnými funkcemi
cviceni/cviceni5_pyquest_uklid.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: stejná hra, čtyři přehledné soubory.


Řešení 5 — jedna z možných variant
reseni/reseni5_pyquest_uklid.py
Tenhle kód potřebuje ukládat soubory, což v prohlížeči nejde — spusť ho na počítači příkazem streamlit run.


4. Domácí úkol

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

Vytvoř soubor nastroje.py a přesuň do něj alespoň tři pomocné funkce, které používáš v aplikaci. Na jeho konec přidej if __name__ == "__main__": s testem každé funkce. Spusť v terminálu python nastroje.py a přines výpis (nebo screenshot).

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_ukol15.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 17Oficiální dokumentace4. Domácí úkol

Oficiální dokumentace se hodí, když si chceš ověřit, jak Python hledá moduly, co přesně dělá import nebo jak funguje __name__ == "__main__". U modulů se vyplatí dívat hlavně na názvy kapitol a krátké příklady.

Co jsme použili Oficiální dokumentace Co tam najdeš
moduly Modules proč rozdělovat kód do souborů a jak moduly používat
import The import statement přesný význam různých zápisů importu
balíčky Packages jak se větší projekty skládají z více modulů
__name__ == "__main__" __main__ kdy se soubor spouští přímo a kdy je jen importovaný
json json ukládání slovníků, čtení JSONu a převod dat

5. Umíme informatiku

Cvičení Odkaz Proč se hodí
Programování v Pythonu umimeinformatiku.cz Struktura programu
Tabulky umimeinformatiku.cz Data odděleně od logiky
Algoritmické myšlení umimeinformatiku.cz Rozklad problému
Kódování a modelování umimeinformatiku.cz Reprezentace dat