← Přehled všech hodin

Soubory a JSON — ukládání hry

Cíl hodiny: Děti chápou rozdíl mezi pamětí a diskem a umí uložit i načíst stav hry.
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. Část pro učitele

Blok 1Proč to potřebujeme1. Část pro učitele

1.1 Proč to potřebujeme

Doteď se všechno ztratilo, jakmile jsi zavřel prohlížeč nebo restartoval program. session_state je paměť. Paměť se vypnutím vymaže. Když chceš, aby něco zůstalo napořád, musíš to napsat na disk.

Analogie, která funguje: paměť je tabule ve třídě, soubor je sešit. Tabuli po hodině smažete, sešit si odnesete domů.

Blok 2Zápis do souboru1. Část pro učitele

1.2 Zápis do souboru

import streamlit as st

with open("hra.txt", "w", encoding="utf-8") as soubor:
    soubor.write("Arkon má 100 životů\n")

st.write("Soubor byl uložen.")

Rozeberte to slovo po slovu:

Část Význam
open("hra.txt", ...) otevři soubor s tímhle jménem
"w" režim zápis (write)
encoding="utf-8" aby fungovala háčky a čárky
with ... as soubor po skončení bloku soubor sám zavře
soubor.write(...) zapiš text

with je důležité. Zajistí, že se soubor zavře, i když v programu nastane chyba. Bez toho zůstane soubor otevřený a data se nemusí zapsat.

Kódování je pro češtinu povinné. Bez encoding="utf-8" můžete na některých systémech dostat rozsypaný čaj nebo UnicodeDecodeError.

Blok 3Režimy otevření1. Část pro učitele

1.3 Režimy otevření

Pozor na "w". Smaže celý původní obsah, i když zapíšeš jen jedno písmeno. Když chceš přidávat, použij "a".

Tohle si vyzkoušej prakticky — je to nezapomenutelné, když si přepíšeš uložený deník.

Blok 4Čtení souboru1. Část pro učitele

1.4 Čtení souboru

import streamlit as st

with open("hra.txt", "w", encoding="utf-8") as soubor:
    soubor.write("Arkon má 100 životů\nBela má 80 životů\n")

with open("hra.txt", "r", encoding="utf-8") as soubor:
    obsah = soubor.read()          # celý soubor jako jeden text

with open("hra.txt", "r", encoding="utf-8") as soubor:
    radky = soubor.readlines()     # seznam řádků

with open("hra.txt", "r", encoding="utf-8") as soubor:
    for radek in soubor:           # po řádcích, šetří paměť
        st.write(radek.strip())

.strip() je tady důležitý — každý řádek ze souboru má na konci \n.

Blok 5Ošetření chyby, když soubor není1. Část pro učitele

1.5 Ošetření chyby, když soubor není

import os
import streamlit as st

if os.path.exists("hra.txt"):
    with open("hra.txt", encoding="utf-8") as f:
        obsah = f.read()
    st.write(obsah)
else:
    st.warning("Soubor zatím neexistuje.")

Druhá varianta, kterou je dobré ukázat, protože ji uvidí všude:

import streamlit as st

try:
    with open("hra.txt", encoding="utf-8") as f:
        obsah = f.read()
except FileNotFoundError:
    obsah = ""
    st.warning("Soubor neexistuje, začínáme od nuly.")

st.write(obsah)

try znamená „zkus tohle". except znamená „a když to selže kvůli tomuhle, udělej radši tohle". Program pak nespadne.

Toto je první setkání s ošetřením chyb. Nejděte do hloubky, stačí tenhle jeden vzor.

Blok 6Proč nestačí obyčejný text1. Část pro učitele

1.6 Proč nestačí obyčejný text

Podívej se na problém:

import streamlit as st

hrdina = {"jmeno": "Arkon", "zivoty": 100}
with open("hra.txt", "w", encoding="utf-8") as soubor:
    soubor.write(str(hrdina))    # zapíše: {'jmeno': 'Arkon', 'zivoty': 100}

st.write(str(hrdina))

Zapsat to umíš. Ale jak to přečteš zpátky jako slovník? Museli bychom ten text rozebírat po znacích. To je práce navíc a plná chyb.

Blok 7JSON — formát pro data1. Část pro učitele

1.7 JSON — formát pro data

JSON je způsob, jak zapsat slovník nebo seznam jako text tak, aby se dal spolehlivě přečíst zpátky. Používá ho celý internet.

Parametry, které se hodí znát:

Parametr Co dělá
ensure_ascii=False nechá české znaky čitelné (jinak \u00e1)
indent=2 pěkné odsazení, aby to šlo číst očima

Pomůcka na zapamatování dumps vs loads:

dumps = dump string — vysypeš data do textu. loads = load string — načteš data z textu. To „s" na konci znamená string. Bez „s" (json.dump) se pracuje rovnou se souborem.

Blok 8Uložení a načtení celé hry1. Část pro učitele

1.8 Uložení a načtení celé hry

import json
import streamlit as st

def uloz(hrdina, cesta="ulozeno.json"):
    with open(cesta, "w", encoding="utf-8") as f:
        json.dump(hrdina, f, ensure_ascii=False, indent=2)


def nacti(cesta="ulozeno.json"):
    try:
        with open(cesta, encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return None

uloz({"jmeno": "Arkon", "zivoty": 100})
st.write(nacti())

Tohle je hotový recept, který můžeš použít ve svém projektu.

Blok 9Streamlit: stahování a nahrávání1. Část pro učitele

1.9 Streamlit: stahování a nahrávání

Toto je pro webovou aplikaci důležitější než zápis na disk serveru:

V opravdové webové aplikaci nemůžeš ukládat na disk uživatele. Proto se hra stáhne jako soubor a při pokračování se zase nahraje. Přesně takhle to dělají opravdové hry v prohlížeči.

Blok 10Co jde a nejde do JSON1. Část pro učitele

1.10 Co jde a nejde do JSON

Jde Nejde
dict, list, str, int, float, bool, None set, funkce, objekty tříd, datetime

Když to nejde uložit, převeď to na něco, co jde. Množinu na seznam, datum na text.

Poznámky pro učiteleTechnické pozadí pro učitele1. Část pro učitele

1.11 Technické pozadí pro učitele

  • with používá kontextový manažer (__enter__/__exit__), obdoba using v C#.
  • JSON klíče jsou vždy řetězce. json.dumps({1: "a"}) udělá z jedničky "1" a po načtení už to bude text. Klasický zdroj překvapení.
  • Relativní cesta se počítá od místa spuštění streamlit run, ne od souboru. Bezpečnější je pathlib.Path(__file__).parent / "data.json".
  • Na Streamlit Community Cloud je souborový systém dočasný — po restartu je pryč. Proto je download_button správnější řešení než zápis na disk.
  • json.load(soubor) na UploadedFile funguje, protože je to file-like objekt.
Poznámky pro učiteleČasté chyby1. Část pro učitele

1.12 Časté chyby

Chyba Příčina Řešení
FileNotFoundError Soubor neexistuje nebo špatná cesta try/except nebo os.path.exists
Rozsypaná čeština Chybí encoding="utf-8" Doplnit u open
\u00e1 místo „á" v JSON Chybí ensure_ascii=False Doplnit u dumps
Soubor je prázdný Zapomenuté with / nezavřený soubor Používat with
Data se přepsala Režim "w" místo "a" Změnit režim
TypeError: not JSON serializable Nepodporovaný typ Převést na seznam/text
JSONDecodeError Poškozený nebo prázdný soubor try/except


2. Ukázky pro projekci

Blok 11Ukázka 1 — Zápis a čtení textu2. Ukázky pro projekci
demo/demo1_soubory.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 12Ukázka 2 — JSON krok za krokem2. Ukázky pro projekci
demo/demo2_json.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 13Ukázka 3 — Uložit a načíst hru2. Ukázky pro projekci
demo/demo3_ulozeni.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 14Cvičení 1 — Deník do souboru (15 min)3. Cvičení na hodinu

Zadání:

  1. Přidej st.text_input na zápis události
  2. Tlačítkem zapiš text do souboru denik.txt v režimu "a"
  3. Nezapomeň na encoding="utf-8" a odřádkování \n
  4. Načti a zobraz celý soubor pod formulářem
  5. Přidej tlačítko, které soubor smaže pomocí os.remove
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4 s os.path.exists
Výzva Bod 5 + počítadlo řádků a znaků

Očekávaný výsledek: deník, který přežije restart aplikace.

cviceni/cviceni1_denik_soubor.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.
Na co si dát pozor
  • Nejčastější chyba je zapomenuté encoding="utf-8" při zápisu i čtení.
  • Vyzkoušej rozdíl mezi režimy a a w na skutečném souboru.
  • Přidej odřádkování \n, jinak se deník slije.
Řešení 1 — jedna z možných variant
reseni/reseni1_denik_soubor.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í 2 — Nejlepší skóre (20 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř soubor skore.json, ve kterém bude seznam slovníků {"jmeno": ..., "body": ...}
  2. Přidej formulář na zadání jména a bodů
  3. Po odeslání načti stávající skóre, přidej nové a ulož zpátky
  4. Seřaď tabulku podle bodů sestupně a zobraz nejlepších pět
  5. Ošetři případ, kdy soubor ještě neexistuje
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4 se sorted(..., key=...)
Výzva Bod 5 pomocí try/except + medaile pro první tři

Očekávaný výsledek: žebříček, který se hromadí mezi spuštěními.

cviceni/cviceni2_skore.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
  • Struktura JSON musí být seznam záznamů; snadno se stane, že omylem uložíš jen poslední hodnotu.
  • Ošetři neexistující soubor dřív, než se začne řadit tabulka výsledků.
  • U řazení použij key= a reverse=True pro sestupné pořadí.
Řešení 2 — jedna z možných variant
reseni/reseni2_skore.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 16Cvičení 3 — Export postavy (20 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř formulář na postavu (jméno, povolání, statistiky, inventář)
  2. Poskládej z toho slovník a zobraz ho přes st.json
  3. Převeď slovník na text pomocí json.dumps(..., ensure_ascii=False, indent=2)
  4. Přidej st.download_button na stažení souboru .json
  5. Přidej st.file_uploader na načtení postavy zpět
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + ověření, že nahraný soubor obsahuje všechny potřebné klíče

Očekávaný výsledek: postava se dá stáhnout a v jiné záložce zase načíst.

cviceni/cviceni3_export.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
  • U exportu zkontroluj, že se používá ensure_ascii=False, aby zůstala čeština čitelná.
  • Nahraný soubor je vhodné validovat na povinné klíče před použitím.
  • Pamatuj na rozdíl mezi json.dumps (text) a json.dump (soubor).
Řešení 3 — jedna z možných variant
reseni/reseni3_export.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í 4 — Bestiář ze souboru (20 min)3. Cvičení na hodinu

Zadání:

  1. Vytvoř v kódu seznam příšer a ulož ho do bestiar.json
  2. Načti ho zpátky a zobraz jako st.dataframe
  3. Přidej formulář na přidání nové příšery a ulož po každém přidání
  4. Přidej možnost příšeru smazat podle jména
  5. Ošetři situace, kdy je soubor prázdný nebo poškozený
Úroveň Co má zvládnout
Minimum Body 1–2
Rozšíření Body 3–4
Výzva Bod 5 s try/except json.JSONDecodeError

Očekávaný výsledek: bestiář, který si pamatuje přidané příšery.

cviceni/cviceni4_bestiar_soubor.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
  • U bestiáře často narazíš na poškozený JSON; přidej try/except JSONDecodeError.
  • Po přidání nebo smazání příšery je potřeba data znovu uložit do souboru.
  • Dbej na konzistentní datové typy (zivoty, sila, zlato jako čísla).
Řešení 4 — jedna z možných variant
reseni/reseni4_bestiar_soubor.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 18Cvičení 5 — PyQuest: uložení hry (25 min)3. Cvičení na hodinu

Zadání:

  1. Napiš funkci uloz_hru() vracející JSON text celého stavu hry
  2. Napiš funkci nacti_hru(data), která stav obnoví do session_state
  3. Přidej do postranního panelu st.download_button na uložení
  4. Přidej st.file_uploader a tlačítko „Načíst hru"
  5. Uložený stav musí obsahovat hrdinu, inventář, deník i počet výprav
Úroveň Co má zvládnout
Minimum Body 1–3
Rozšíření Bod 4
Výzva Bod 5 + verze uložení a kontrola, že soubor patří k této hře

Očekávaný výsledek: hra se dá uložit, zavřít prohlížeč a pokračovat později.

cviceni/cviceni5_pyquest_ulozeni.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
  • Při ukládání celé hry ohlídej stabilní strukturu slovníku (verze, hrdina, deník, výpravy).
  • Načtení má kontrolovat verzi/klíče, jinak může starý soubor rozbít aplikaci.
  • Snadno zapomeneš po načtení zavolat st.rerun, takže změna není vidět.
Řešení 5 — jedna z možných variant
reseni/reseni5_pyquest_ulozeni.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 19Domácí úkol na příští hodinu4. Domácí úkol

Uprav ukládání tak, aby si hra pamatovala datum a čas uložení. Použij from datetime import datetime a datetime.now().isoformat(). Při načtení zobraz, jak stará uložená pozice je.

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

Oficiální dokumentace se hodí, když si chceš ověřit, jak se správně otevírá soubor, co dělají režimy r / w / a, nebo jak Python převádí slovníky a seznamy do JSONu. Je v angličtině, ale dobře se v ní hledá podle názvu funkce a krátkých příkladů.

Co jsme použili Oficiální dokumentace Co tam najdeš
open() open otevření souboru, režimy, kódování a další parametry
with The with statement proč se soubor po skončení bloku správně zavře
modul json json přehled práce s JSONem v Pythonu
json.dump / json.load Basic usage ukládání do souboru a načítání zpět
json.dumps / json.loads Encoders and Decoders převod mezi Python daty a textem
FileNotFoundError FileNotFoundError co znamená chyba, když soubor ještě neexistuje
st.download_button st.download_button stažení uložené hry jako souboru
st.file_uploader st.file_uploader nahrání JSON souboru zpět do aplikace

5. Umíme informatiku

Blok 21Navazující cvičení na Umíme informatiku5. Umíme informatiku
Cvičení Odkaz Proč se hodí
Kódování a modelování umimeinformatiku.cz Reprezentace dat a formáty
Tabulky umimeinformatiku.cz Strukturovaná data
Programování v Pythonu umimeinformatiku.cz Práce s daty
Doplňování textu umimeinformatiku.cz Přesná syntaxe