open, with, režimy r/w/a, kódování UTF-8, json.dumps/loads, ošetření chybDoteď se všechno ztratilo, jakmile jsi zavřel prohlížeč nebo restartoval program.
session_stateje 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ů.
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 |
withje 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.
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.
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.
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)
tryznamená „zkus tohle".exceptznamená „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.
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.
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.
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.
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.
| 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.
with používá kontextový manažer (__enter__/__exit__), obdoba using v C#.json.dumps({1: "a"}) udělá z jedničky "1"
a po načtení už to bude text. Klasický zdroj překvapení.streamlit run, ne od souboru.
Bezpečnější je pathlib.Path(__file__).parent / "data.json".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.| 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 |
streamlit run.Zadání:
- Přidej
st.text_inputna zápis události- Tlačítkem zapiš text do souboru
denik.txtv režimu"a"- Nezapomeň na
encoding="utf-8"a odřádkování\n- Načti a zobraz celý soubor pod formulářem
- 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.
streamlit run.encoding="utf-8" při zápisu i čtení.a a w na skutečném souboru.\n, jinak se deník slije.streamlit run.Zadání:
- Vytvoř soubor
skore.json, ve kterém bude seznam slovníků{"jmeno": ..., "body": ...}- Přidej formulář na zadání jména a bodů
- Po odeslání načti stávající skóre, přidej nové a ulož zpátky
- Seřaď tabulku podle bodů sestupně a zobraz nejlepších pět
- 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.
key= a reverse=True pro sestupné pořadí.streamlit run.Zadání:
- Vytvoř formulář na postavu (jméno, povolání, statistiky, inventář)
- Poskládej z toho slovník a zobraz ho přes
st.json- Převeď slovník na text pomocí
json.dumps(..., ensure_ascii=False, indent=2)- Přidej
st.download_buttonna stažení souboru.json- Přidej
st.file_uploaderna 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.
ensure_ascii=False, aby zůstala čeština čitelná.json.dumps (text) a json.dump (soubor).Zadání:
- Vytvoř v kódu seznam příšer a ulož ho do
bestiar.json- Načti ho zpátky a zobraz jako
st.dataframe- Přidej formulář na přidání nové příšery a ulož po každém přidání
- Přidej možnost příšeru smazat podle jména
- 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.
try/except JSONDecodeError.zivoty, sila, zlato jako čísla).streamlit run.Zadání:
- Napiš funkci
uloz_hru()vracející JSON text celého stavu hry- Napiš funkci
nacti_hru(data), která stav obnoví dosession_state- Přidej do postranního panelu
st.download_buttonna uložení- Přidej
st.file_uploadera tlačítko „Načíst hru"- 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.
st.rerun, takže změna není vidět.Uprav ukládání tak, aby si hra pamatovala datum a čas uložení. Použij
from datetime import datetimeadatetime.now().isoformat(). Při načtení zobraz, jak stará uložená pozice je.
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.
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 |
| 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 |