diff --git a/courses/pyladies.yml b/courses/pyladies.yml
index 1149fda2..4e037f57 100644
--- a/courses/pyladies.yml
+++ b/courses/pyladies.yml
@@ -129,6 +129,7 @@ plan:
- lesson: beginners/dict
- lesson: intro/json
- lesson: projects/github-api
+ - lesson: beginners/dict-with-list-values
- title: Slovníkový tahák
url: https://pyvec.github.io/cheatsheets/dicts/dicts-cs.pdf
type: cheatsheet
diff --git a/lessons/beginners/dict-with-list-values/index.md b/lessons/beginners/dict-with-list-values/index.md
new file mode 100644
index 00000000..460b64d8
--- /dev/null
+++ b/lessons/beginners/dict-with-list-values/index.md
@@ -0,0 +1,63 @@
+# Více hodnot v jednom záznamu slovníku
+
+Ke každému klíči může patřit jen jedna hodnota.
+Jak bys zařídil{{a}}, aby hodnot bylo víc?
+
+Řekněme, že bys chtěl{{a}} do slovníku uložit tyto telefonní kontakty:
+
+* Katka:
+ * 4925219
+* Jirka:
+ * 7477058
+ * 3251156
+* Verča:
+ * 1019103
+
+Jak na to?
+Jednoduchý slovník použít nemůžeš. Pozor na následující zápis!
+
+```python
+kontakty = {
+ 'Katka': '4925219',
+ 'Jirka': '7477058',
+ 'Jirka': '3251156',
+ 'Verča': '1019103',
+}
+```
+
+Python v tomto případě jednotlivé záznamy uloží postupně, jako kdybys napsal{{a}}:
+
+```python
+kontakty = {}
+kontakty['Katka'] = '4925219'
+kontakty['Jirka'] = '7477058'
+kontakty['Jirka'] = '3251156'
+kontakty['Verča'] = '1019103'
+```
+
+A ve výsledku bude mít `'Jirka'` uložené jen jedno číslo.
+Python tohle nenahlásí jako chybu, ačkoli to často není to, co chceš.
+
+Protože ve slovníku může být každému klíči přiřazena jen jedna hodnota,
+bude potřeba více hodnot směstnat do jedné.
+Každému kontaktu můžeš přiřadit *seznam* čísel:
+
+```python
+kontakty = {
+ 'Katka': ['4925219'],
+ 'Jirka': ['7477058', '3251156'],
+ 'Verča': ['1019103'],
+}
+```
+
+Výraz jako `kontakty['Katka']` pak označuje seznam.
+Pokud se Katka přestěhuje do zahraničí a pořídí si nové číslo,
+můžeš napsat:
+
+```python
+kontakty['Katka'].append('+897 3788509')
+print(len(kontakty['Katka']))
+print(kontakty['Katka'][-1])
+del kontakty['Katka'][0]
+print(kontakty['Katka'])
+```
diff --git a/lessons/beginners/dict-with-list-values/info.yml b/lessons/beginners/dict-with-list-values/info.yml
new file mode 100644
index 00000000..3a533721
--- /dev/null
+++ b/lessons/beginners/dict-with-list-values/info.yml
@@ -0,0 +1,5 @@
+title: Víc hodnot v jednom záznamu slovníku
+style: md
+attribution:
+- Pro PyLadies CZ napsal Petr Viktorin, 2015-2021.
+license: cc-by-sa-40
diff --git a/lessons/beginners/dict/index.md b/lessons/beginners/dict/index.md
index c1248c62..b875e373 100644
--- a/lessons/beginners/dict/index.md
+++ b/lessons/beginners/dict/index.md
@@ -2,154 +2,155 @@
Další základní datový typ, který si představíme –
po číslech, řetězcích, seznamech a n-ticích –
-jsou *slovníky* (angl. *dictionary*, `dict`).
+je *slovník* (angl. *dictionary*, `dict`).
-Podobně jako seznamy, slovníky v sobě obsahují další hodnoty.
-Na rozdíl od seznamů, ve kterých jsou všechny prvky
-uspořádané do jedné sekvence, ve slovnících máme dva druhy
-prvků: takzvaný *klíč* (angl. *key*) a *hodnotu* (angl. *value*).
-Každému klíči je přiřazena jedna hodnota.
+Představ si překladový slovník, třeba tenhle česko-anglický:
-Slovník můžeš použít, když máš několik kousků
-informací, které se dají pojmenovat, ale chceš s nimi
-pracovat jako s jednou proměnnou.
+* **Jablko**: Apple
+* **Knoflík**: Button
+* **Myš**: Mouse
-Tady je slovník, který má tři klíče, a k nim příslušné tři hodnoty:
+Slovník v Pythonu obsahuje *záznamy*. Každý záznam přiřazuje
+nějakému *klíči* nějakou *hodnotu*.
+V našem příkladu je klíči *Jablko* přiřazena hodnota *Apple*,
+klíči *Knoflík* náleží hodnota *Button*
+a klíč *Myš* ukazuje na *Mouse*.
-```pycon
->>> ja = {'jméno': 'Anna', 'město': 'Brno', 'čísla': [3, 7]}
+V Pythonu by se takový slovník napsal následovně:
+
+``` pycon
+>>> slovnik = {'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
+>>> slovnik
+{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
+```
+Pozor na všechny ty symboly!
+V tomhle slovníku jsou klíče i hodnoty řetězce, takže jsou v uvozovkách.
+Každý klíč je od své hodnoty oddělený dvojtečkou;
+jednotlivé dvojice jsou od sebe oddělené čárkou.
+A celý slovník je uzavřený ve složených závorkách.
+
+Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět co hledat.
+Konkrétně potřebuješ *klíč*.
+Ten dáš do hranatých závorek:
+
+``` pycon
+>>> slovnik['Jablko']
+'Apple'
```
-{# XXX - Only visible on Python 3.5 and below. How to teach this?
-Když slovník vypíšeš, pravděpodobně zjistíš,
-se klíče a hodnoty vypíšou v jiném pořadí.
-Slovníky totiž, na rozdíl od seznamů, nemají dané
-pořadí prvků – jen přiřazují hodnoty klíčům.
-#}
+Je to podobné jako u seznamů, jen v hranatých závorkách není index
+(pořadové číslo prvku) nebo rozmezí s dvojtečkou, ale právě klíč.
-Hodnoty ze slovníku můžeš získat podobně jako
-ze seznamu, jen místo indexu (pozice) použiješ klíč:
+> [note]
+> Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč.
+> Na překlad z angličtiny do češtiny bys potřeboval{{a}} druhý slovník.
-```pycon
->>> ja['jméno']
-'Anna'
-```
+## Měnění slovníků
-Zeptáš-li se na neexistující klíč, nebude se to Pythonu líbit:
+Co se stane, když klíč ve slovníku není?
-```pycon
->>> ja['věk']
+``` pycon
+>>> slovnik['Pes']
Traceback (most recent call last):
- File "", line 1, in <module>
-KeyError: 'věk'
+ File "", line 1, in
+KeyError: 'Pes'
```
-Hodnoty jdou podle klíče i měnit:
+Python si postěžuje na `KeyError` – chybu klíče.
-```pycon
->>> ja['čísla'] = [3, 7, 42]
->>> ja
-{'jméno': 'Anna', 'město': 'Brno', 'čísla': [3, 7, 42]}
+Podobně jako seznamy se ale slovníky dají měnit.
+Nový záznam vytvoříš takhle:
+
+``` pycon
+>>> slovnik['Pes'] = 'Dog'
+>>> slovnik
+{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Dog'}
```
-... nebo přidávat:
+> [note]
+> Na rozdíl od překladového slovníku nemusí být Pythonní slovník seřazený
+> podle abecedy.
+> Není to potřeba, počítač umí rychle vyhledávat i bez seřazení.
-```pycon
->>> ja['jazyk'] = 'Python'
->>> ja
-{'jméno': 'Anna', 'město': 'Brno', 'čísla': [3, 7, 42], 'jazyk': 'Python'}
+Kdybys potřeboval{{a}} změnit už existující záznam, použij stejný příkaz.
+K jednomu klíči může být přiřazena jen jedna hodnota.
+
+``` pycon
+>>> slovnik['Pes'] = 'Power strip'
+>>> slovnik
+{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Power strip'}
```
-... nebo ubírat příkazem `del`, podobně jako u seznamů:
+Chceš-li ze slovníku nějaký záznam smazat, dělá se to podobně jako
+u seznamů – příkazem `del`:
-```pycon
->>> del ja['čísla']
->>> ja
-{'jméno': 'Anna', 'město': 'Brno', 'jazyk': 'Python'}
+``` pycon
+>>> del slovnik['Pes']
+>>> slovnik
+{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
```
-## Vyhledávací tabulka
+Když budeš chtít zjistit, kolik je ve slovníku záznamů,
+zeptáš se podobně jako na počet znaků řetězce nebo prvků seznamu.
+Použiješ funkci `len()`.
-Trochu jiné použití slovníku, než sdružování
-„různých“ typů informací, je takzvaná
-*vyhledávací tabulka* (angl. *lookup table*).
-V ní mají typicky všechny hodnoty stejný typ.
-
-Taková tabulka se hodí vždycky, když je potřeba
-přiřadit nějaké hodnoty jiným hodnotám.
-Jako v telefonním seznamu, kde každému jménu přísluší
-nějaké číslo, nebo v překladovém slovníku, kde jsou slovům
-přiřazeny překlady.
+``` pycon
+>>> len(slovnik)
+3
+```
-```python
-cisla = {
- 'Maruška': '153 85283',
- 'Terka': '237 26505',
- 'Renata': '385 11223',
- 'Michal': '491 88047',
-}
+A pomocí `in` můžeš zjistit, jestli slovník obsahuje daný klíč.
+Funguje to opravdu jen pro klíče, ne pro přiřazené hodnoty:
-barvy = {
- 'hruška': 'zelená',
- 'jablko': 'červená',
- 'meloun': 'zelená',
- 'švestka': 'modrá',
- 'ředkvička': 'červená',
- 'zelí': 'zelená',
- 'mrkev': 'červená',
-}
+``` pycon
+>>> 'Myš' in slovnik
+True
+>>> 'Mouse' in slovnik
+False
```
## Iterace
-Když dáš slovník do cyklu `for`, dostaneš klíče:
+Když slovník projdeš cyklem `for`, dostaneš *klíče* jednotlivých záznamů:
```pycon
->>> popisy_funkci = {'len': 'délka', 'str': 'řetězec', 'dict': 'slovník'}
->>> for klic in popisy_funkci:
+>>> for klic in slovnik:
... print(klic)
-str
-dict
-len
+Jablko
+Knoflík
+Myš
```
-Pokud chceš hodnoty, stačí použít metodu `values`:
+Kdybys chtěl{{a}} projít místo klíčů hodnoty, použij metodu `values`,
+která vrací iterátor hodnot:
```pycon
->>> for hodnota in popisy_funkci.values():
+>>> for hodnota in slovnik.values():
... print(hodnota)
-řetězec
-slovník
-délka
+Apple
+Button
+Mouse
```
Většinou ale potřebuješ jak klíče tak hodnoty.
-K tomu mají slovníky metodu `items`,
-která bude v cyklu `for` dávat dvojice:
+K tomu mají slovníky metodu `items`, která vrací iterátor dvojic.
+Často využiješ možnost každou dvojici přímo rozbalit v cyklu `for`,
+jako se to dělá se `zip` nebo `enumerate`:
```pycon
->>> for klic, hodnota in popisy_funkci.items():
+>>> for klic, hodnota in slovnik.items():
... print('{}: {}'.format(klic, hodnota))
-str: řetězec
-dict: slovník
-len: délka
+Jablko: Apple
+Knoflík: Button
+Myš: Mouse
```
-> [note]
-> Existuje i metoda `keys()`, která vrací klíče.
->
-> To, co `keys()`, `values()` a `items()` vrací, jsou speciální objekty,
-> které kromě použití ve `for` umožňují další
-> operace: například pracovat s klíči jako s množinou.
-> V [dokumentaci](https://docs.python.org/3.0/library/stdtypes.html#dictionary-view-objects)
-> Pythonu je to všechno popsáno.
-
-V průběhu takového `for` cyklu nesmíš
+V průběhu iterace (tedy v rámci `for` cyklu) nesmíš
do slovníku přidávat záznamy, ani záznamy odebírat:
```python
->>> for klic in popisy_funkci:
-... del popisy_funkci[klic]
+>>> for klic in slovnik:
+... del slovnik[klic]
Traceback (most recent call last):
File "", line 1, in
RuntimeError: dictionary changed size during iteration
@@ -157,34 +158,37 @@ RuntimeError: dictionary changed size during iteration
Hodnoty u už existujících klíčů ale měnit můžeš.
-
## Jak udělat slovník
-Slovník se dá vytvořit dvěma způsoby.
-První, pomocí {složených závorek}, jsme už viděl{{gnd('i', 'y', both='i')}};
-další využívají funkci `dict`.
-Ta, ve stylu `str`, `int` či `list`, převede cokoli, co jde, na slovník.
+Slovník se dá vytvořit několika způsoby.
+První, pomocí složených závorek, jsi už viděl{{a}}.
+Další způsob využívá funkci `dict`.
+Ta, ve stylu `str`, `int` či `list`, převede cokoli co jde na slovník.
Slovník je ovšem dost specifická struktura –
-čísla nebo typické seznamy na něj převádět nejdou.
-Můžeme ale na slovník převést *jiný slovník*.
-Nový slovník žije svým vlastním životem;
-následné změny se promítnou jen do něj.
+čísla ani většina seznamů na něj převést nejdou.
+Můžeš ale na slovník převést *jiný slovník*.
+Nový slovník pak žije svým vlastním životem;
+můžeš ho měnit nezávisle na tom původním.
-```python
-barvy_po_tydnu = dict(barvy)
-for klic in barvy_po_tydnu:
- barvy_po_tydnu[klic] = 'černo-hnědo-' + barvy_po_tydnu[klic]
-print(barvy['jablko'])
-print(barvy_po_tydnu['jablko'])
-```
Druhá věc, která jde převést na slovník, je
-*sekvence dvojic* klíč/hodnota:
+*sekvence dvojic* klíč/hodnota – ať už seznam:
-```python
-data = [(1, 'jedna'), (2, 'dva'), (3, 'tři')]
-nazvy_cisel = dict(data)
+```pycon
+>>> data = [(1, 'jedna'), (2, 'dva'), (3, 'tři')]
+>>> nazvy_cisel = dict(data)
+>>> nazvy_cisel
+{1: 'jedna', 2: 'dva', 3: 'tři'}
+```
+
+nebo jiný iterovatelný objekt:
+
+```pycon
+>>> data = enumerate(['nula', 'jedna', 'dva'])
+>>> nazvy_cisel = dict(data)
+>>> nazvy_cisel
+{0: 'nula', 1: 'jedna', 2: 'dva'}
```
A to je vše, co se na slovník dá převést.
@@ -205,8 +209,79 @@ print(popisy_funkci['len'])
> Například takhle nejde zadat jako klíč řetězec
> `"def"` nebo `"propan-butan"`.
-Pojmenované argumenty jde kombinovat s ostatními
-způsoby vytvoření `dict`.
+
+### Zaplň prázdný slovník
+
+Nejobecnější způsob vytváření slovníků je podobný tomu co znáš u seznamů:
+vytvoř prázdný slovník a postupně do něj přidávej záznamy, jeden za druhým.
+
+Řekněme, že máš slovník, který přiřazuje ovoci jeho barvu:
+
+```python
+barvy = {
+ 'hruška': 'zelená',
+ 'jablko': 'červená',
+ 'meloun': 'zelená',
+ 'švestka': 'modrá',
+ 'ředkvička': 'červená',
+ 'zelí': 'zelená',
+ 'mrkev': 'červená',
+}
+```
+
+Následující kód vytvoří slovník se změněnými barvami:
+
+```python
+barvy_po_tydnu = {}
+for ovoce, barva in barvy.items():
+ barvy_po_tydnu[ovoce] = 'černo-hnědo-' + barva
+
+print(barvy_po_tydnu['jablko'])
+```
+
+
+## Typy klíčů a hodnot
+
+Do slovníku můžeš uložit jakoukoli hodnotu: řetězce, seznamy, nebo čísla.
+
+```python
+uzivatel = {'jméno': 'Amálka', 'velikost nohy': 36, 'oblíbená čísla': [5, 27]}
+```
+
+Jako *klíč* jde ovšem použít jen hodnoty, podle kterých pak Python umí záznam
+rychle najít.
+A to nejsou všechny. Řetězce a čísla použít jdou:
+
+```python
+jmena_cisel = {2: 'dva', 3: 'tři'}
+```
+
+Ale seznamy nebo jiné slovníky ne.
+Typy které se dají použít jako klíč ve slovníku se technicky označují jako
+„*hashovatelné*“ (angl. *hashable*).
+Tento termín se objevuje v chybových hláškách:
+
+```pycon
+>>> jmena_seznamu = {[1, 2, 3]: 'čísla', ['a', 'b', 'c']: 'řetězce'}
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: unhashable type: 'list'
+```
+
+N-tice jsou hashovatelné, pokud obsahují jen hashovatelné hodnoty:
+
+```pycon
+>>> figurky = {('c', 1): 'bílý střelec', ('e', 8): 'černý král'}
+>>> figurky['c', 1]
+'bílý střelec'
+```
+
+```pycon
+>>> jmena = {([1, 2, 3], [3, 4, 5]): 'dvojice seznamů'}
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: unhashable type: 'list'
+```
## A to je zatím ke slovníkům vše
diff --git a/lessons/beginners/dict/info.yml b/lessons/beginners/dict/info.yml
index a7e30478..77017d2d 100644
--- a/lessons/beginners/dict/info.yml
+++ b/lessons/beginners/dict/info.yml
@@ -1,4 +1,11 @@
title: Slovníky
style: md
-attribution: Pro PyLadies Brno napsal Petr Viktorin, 2015-2017.
+attribution:
+- Část této kapitoly je založena na materiálech [DjangoGirls](https://djangogirls.org/).
+- |
+ Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků.
+ Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové,
+ Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové,
+ Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi.
+- Pro PyLadies CZ upravil Petr Viktorin, 2015-2021.
license: cc-by-sa-40
diff --git a/lessons/intro/json/index.md b/lessons/intro/json/index.md
index 8e200996..01cd8703 100644
--- a/lessons/intro/json/index.md
+++ b/lessons/intro/json/index.md
@@ -1,41 +1,44 @@
-# JSON
+# Kódování dat
-Existují i jiné programovací jazyky než Python.
+V Pythonu informace spravuješ v seznamech, slovnících a jiných datových
+strukturách.
+Když si vytvoříš nějaký slovník plný seznamů, řetězců a čísel,
+můžeš s ním v Pythonu dál pracovat. Třeba:
-Ostatní jazyky neumí pracovat s pythonními hodnotami.
-Budeš-li se chtít s takovými programy „domluvit” –
-předat jim nějaké informace ke zpracování
-nebo od nich dostat výsledky –
-musíš informace předávat v nějaké zjednodušené podobě.
-
-
-## Typy
+```python
+data = {
+ 'jméno': 'Anna',
+ 'město': 'Brno',
+ 'jazyky': ['čeština', 'angličtina'],
+ 'věk': 26,
+}
+data['jazyky'].append('Python')
+```
-Většina programovacích jazyků má nějaká čísla, nějaký druh seznamů,
-nějakou odrůdu řetězců a nějakou variaci na slovníky
-(nebo několik způsobů jak slovníky vytvořit).
-Dále má spousta jazyků způsob, jak zapsat
-`True`, `False` a `None`.
+Taková data ale nejdou přímo zapsat na disk nebo přenést přes Internet.
+Python si je „pamatuje“ tak, aby s nimi mohl jednoduše pracovat.
+Když ale Python vypneš, informace se ztratí.
-Tyhle základní typy většinou stačí na předání
-jakékoli informace v rozumně čitelné podobě,
-i když ne ve všech jazycích mají přesné ekvivalenty
-(třeba Python má dva základní druhy čísel – `int` a `float`).
-Často se proto v komunikaci omezíme na ně.
+Abys mohl{{a}} informace zapsat, uložit nebo dokonce přenést na jiný počítač,
+musíš je *zakódovat* – převést na řetězec.
+Řetězec pak lze zapsat do souboru nebo třeba poslat přes Internet.
+> [note]
+> Doopravdy se do souborů zapisují (a po síti posílají)
+> sekvence *bytů* (čísel od 0 do 255).
+> Python řetězce na byty ale převádí automaticky (pomocí kódování
+> nastaveného pomocí `encoding` při otevření souboru).
+> Vystačíš si proto s převáděním na řetězce, se kterými – na rozdíl od bytů
+> – už umíš pracovat.
-## Kódování dat
-Další problém je přenos dat:
-abys mohl{{a}} informace zapsat na disk nebo přenést
-přes Internet, musíš je převést na sekvenci *bytů* (čísel od 0 do 255).
-Zjednodušeně řečeno, musíš je převést na řetězec.
+## Kódování
-Existuje spousta způsobů, jak zakódovat data do textu.
+Existuje spousta způsobů jak zakódovat data do textu.
Každý způsob se snaží najít vhodnou rovnováhu mezi
čitelností pro lidi/počítače, délkou zápisu,
bezpečností, možnostmi a rozšiřitelností.
-My už známe syntaxi Pythonu:
+Už znáš syntaxi Pythonu, kterou můžeš použít jen pro Python:
```python
{
@@ -46,7 +49,7 @@ My už známe syntaxi Pythonu:
}
```
-Jiný způsob zápisu dat je [YAML](http://www.yaml.org/):
+Jiný způsob kódování dat je [YAML](http://www.yaml.org/):
```yaml
jméno: Anna
@@ -64,8 +67,9 @@ Nebo třeba [Bencode](http://en.wikipedia.org/wiki/Bencode):
d6:jazykyl9:čeština11:angličtina6:Pythone4:věki26e6:město4:Brno6:jméno4:Annae
```
-Existují i netextové formáty, jako
-[Pickle 3](https://docs.python.org/3/library/pickle.html):
+Existují i netextové formáty jako
+[Pickle 3](https://docs.python.org/3/library/pickle.html).
+Převedením do textu bys dostal{{a}} „guláš“ jako:
```plain
}q(XjménoqXAnnaqXmÄtoqXBrnoqXjazykyq]q(X ÄeÅ¡tinaqX
@@ -74,7 +78,7 @@ K▒u.
```
A nakonec uvedu [JSON](http://json.org/)
-(z angl. *Javascript Object Notation* „zápis Javascriptových objektů”),
+(z angl. *Javascript Object Notation* „zápis Javascriptových objektů”),
který se pro svou jednoduchost rozšířil na Internetu nejvíc:
```json
@@ -88,51 +92,76 @@ který se pro svou jednoduchost rozšířil na Internetu nejvíc:
> [note]
> Pozor na to, že ačkoli JSON vypadá podobně jako zápis
-> v Pythonu, je to jiný formát s vlastními pravidly.
+> v Pythonu, je to jiný formát s vlastními pravidly.
> Nezaměňuj je!
>
> Aspoň ze začátku nedoporučuji JSON psát ručně;
> nech na počítači, aby dal na správné místo správné
> čárky a uvozovky.
-## JSON v Pythonu
-Kódování objektů v JSONu je jednoduché: existuje modul `json`,
-jehož metoda `loads` načte data z řetězce:
+## JSON
+
+Pojďme se zaměřit na populární JSON; práce s ostatními formáty funguje podobně.
+
+K zakódování dat do textu použij funkci `dumps` z modulu `json`
+(který je potřeba naimportovat).
+
+```pycon
+>>> import json
+>>> kod = json.dumps(data)
+>>> kod
+'{"jm\\u00e9no": "Anna", "m\\u011bsto": "Brno", "jazyky": ["\\u010de\\u0161tina", "angli\\u010dtina", "Python"], "v\\u011bk": 26}'
+```
+
+Výsledný řetězec obsahuje ty správné informace – ale je psaný spíš pro
+počítačové zpracování než k tomu, aby ho četl člověk.
+
+Zapiš tenhle řetězec do souboru:
```python
-import json
+with open('data.json', 'w') as soubor:
+ print(kod, file=soubor)
+```
-json_retezec = """
- {
- "jméno": "Anna",
- "město": "Brno",
- "jazyky": ["čeština", "angličtina", "Python"],
- "věk": 26
- }
-"""
+Jinde – třeba v jiném programu, nebo dokonce na jiném počítači, pokud tam
+soubor zkopíruješ – můžeš pak řetězec s kódem načíst:
-data = json.loads(json_retezec)
-print(data)
-print(data['město'])
+```python
+with open('data.json') as soubor:
+ kod = soubor.read()
```
-A pak tu je metoda `dumps`, která naopak daná data zakóduje
-a vrátí řetězec:
+A pomocí `json.loads` ho pak převedeš zpátky na původní slovník,
+se kterým můžeš dál pracovat:
```pycon
->>> print(json.dumps(data))
-{"v\u011bk": 26, "jm\u00e9no": "Anna", "jazyky": ["\u010de\u0161tina", "angli\u010dtina", "Python"], "m\u011bsto": "Brno"}
+>>> data = json.loads(kod)
+>>> print(data)
+{'jméno': 'Anna', 'město': 'Brno', 'jazyky': ['čeština', 'angličtina', 'Python'], 'věk': 26}
+>>> print(data['věk'] + 1)
+27
```
-To, co vrátí jednoduché zavolání `dumps(data)` je vhodné pro počítačové
-zpracování;
-má-li výsledná data číst člověk, nastav
-`ensure_ascii=False` (aby se písmenka s diakritikou nekódovala pomocí `\`)
+
+### Hezký výstup
+
+To, co vrací `json.dumps`, je vhodné pro počítačové zpracování:
+
+```pycon
+>>> kod = json.dumps(data)
+>>> print(kod)
+{"jm\u00e9no": "Anna", "m\u011bsto": "Brno", "jazyky": ["\u010de\u0161tina", "angli\u010dtina", "Python"], "v\u011bk": 26}
+```
+
+Má-li výsledný soubor číst člověk, je ho možné zpřehlednit
+pomocí pojmenovaných argumentů `ensure_ascii=False`
+(aby se písmenka s diakritikou nekódovala pomocí `\`)
a `indent=2` (odsazení dvěma mezerami).
```pycon
->>> print(json.dumps(data, ensure_ascii=False, indent=2))
+>>> kod = json.dumps(data, ensure_ascii=False, indent=2)
+>>> print(kod)
{
"věk": 26,
"jméno": "Anna",
@@ -145,6 +174,114 @@ a `indent=2` (odsazení dvěma mezerami).
}
```
-Kompletní popis modulu `json` –
-včetně funkcí na zápis/čtení přímo do/ze souborů –
-je v příslušné [dokumentaci](https://docs.python.org/3/library/json.html).
+Tenhle kód lze taky zapsat do souboru nebo načíst zpět pomocí `json.loads`,
+jen se trochu líp čte lidem.
+
+> [note]
+> Kompletní popis modulu `json` –
+> včetně funkcí na zápis/čtení přímo do/ze souborů –
+> je v příslušné [dokumentaci](https://docs.python.org/3/library/json.html).
+
+
+## Typy
+
+
+JSON neumožňuje věrně zakódovat jakýkoli Pythonní objekt.
+Zaměřuje se na výměnu informací mezi různými programy a programovacími jazyky.
+
+Ostatní jazyky často neumí přímo pracovat s pythonními hodnotami – seznamy,
+slovníky, `range`, nebo funkcemi.
+Budeš-li se chtít s takovými programy „domluvit” –
+předat jim nějaké informace ke zpracování
+nebo od nich dostat výsledky –
+musíš informace předávat ve zjednodušené podobě.
+
+Většina programovacích jazyků má nějaká čísla, nějaký druh seznamů,
+nějakou odrůdu řetězců a nějakou variaci na slovníky
+(často jen s řetězcovými klíči).
+Dále má spousta jazyků způsob, jak zapsat
+`True`, `False` a `None`.
+
+Tyhle základní typy většinou stačí na předání
+jakékoli informace v rozumně čitelné podobě.
+A tak se v komunikaci často omezíme na ně,
+i když ne všechny jazyky mají přesné ekvivalenty.
+Třeba Python má dva základní druhy sekvencí – seznamy a n-tice – a
+dva druhy čísel – celá (`int`) a reálná (`float`).
+
+Převod na JSON je proto „ztrátový“: po dekódování nedostaneš přesně stejný
+objekt jako ten, který jsi zakódoval{{a}}, ale nějaký podobný.
+Konkrétně modul `json` převádí n-tice na seznamy
+a klíče slovníků převádí na řetězce:
+
+```python
+>>> data = {'dvojice': (1, 2), 'seznam': [3, 4], 2: 'dva', 11: 'jedenáct'}
+>>> kod = json.dumps(data)
+>>> json.loads(kod)
+{'dvojice': [1, 2], 'seznam': [3, 4], '2': 'dva', '11': 'jedenáct'}
+```
+
+
+## Jiná kódování
+
+Jak už bylo řečeno, JSON je jen jeden ze způsobů, kterými lze data zakódovat.
+Jiná kódování mají svá pro a proti, ale v podstatě fungují stejně:
+jedna funkce (často `dumps`) zakóduje Pythonní objekt do řetězce a druhá
+(často `loads`) dekóduje řetězec na původní (nebo podobný) Pythonní objekt.
+
+V případech, kdy má soubor s informacemi psát člověk,
+se často používají formáty [TOML] nebo [YAML].
+
+
+### TOML
+
+Knihovnu pro TOML potřeba si nainstalovat.
+Dělá se to příkazem, který znáš z instalace knihovny Pytest.
+Pozor ve jméně `toml` neudělej překlep, jinak nainstaluješ něco jiného
+(a možná nebezpečného!):
+
+```console
+(venv)$ python -m pip install toml
+```
+
+Data pak lze kódovat pomocí `toml.dumps` a dekódovat pomocí `toml.loads`:
+
+
+```pycon
+>>> import toml
+>>> print(toml.dumps(data))
+"věk" = 26
+"jméno" = "Anna"
+jazyky = ["čeština", "angličtina", "Python"]
+"město" = "Brno"
+```
+
+
+### YAML
+
+Knihovnu pro YAML je také potřeba doinstalovat.
+Opět – ve jméně `pyyaml` neudělej překlep!
+
+```console
+(venv)$ python -m pip install pyyaml
+```
+
+Data pak lze kódovat pomocí `yaml.safe_dump` (nebo „hezky“
+pomocí `yaml.safe_dump(data, indent=4, allow_unicode=True)`)
+a zapisovat pomocí `yaml.safe_load(kod)`.
+Výsledný soubor vypadá takto:
+
+```yaml
+jazyky:
+- čeština
+- angličtina
+- Python
+jméno: Anna
+město: Brno
+věk: 26
+```
+
+
+[JSON]: https://www.json.org
+[TOML]: https://github.com/toml-lang/toml
+[YAML]: https://yaml.org/
diff --git a/lessons/projects/github-api/index.md b/lessons/projects/github-api/index.md
index 803eec6a..56673164 100644
--- a/lessons/projects/github-api/index.md
+++ b/lessons/projects/github-api/index.md
@@ -9,11 +9,11 @@ Spousta webových služeb poskytuje takzvané
programátorské rozhraní), přes které je možné s danou
službou komunikovat programově.
Místo klikání na tlačítka a čtení stránek „očima”
-dostaneme data ve formátu, kterým rozumí počítače –
-a v dnešní době to bude většinou formát JSON.
+dostaneš data ve formátu, kterému rozumí počítače.
+V dnešní době to bude většinou formát JSON.
-Z minulých lekcí bys měl{{a}} mít založený účet na github.com,
-tak se zkusme zeptat Githubu, co o nás ví.
+Z minulých lekcí bys měl{{a}} mít založený účet na github.com.
+Podívejme se na to, jak se zeptat Githubu, co o tobě ví.
## Autorizace
@@ -26,15 +26,18 @@ My to uděláme co nejjednodušeji, ať se rychle dostaneme k jádru věci:
* Přihlaš se na [github.com](https://github.com).
* Jdi na [nastavení Personal Accesss Tokens](https://github.com/settings/tokens).
* Vytvoř si nový token ("Generate new token"). Nezaškrtávej žádná oprávnění navíc.
-* Zkopíruj si heslo, které takto dostaneš, do souboru `token.txt`.
+* Zkopíruj si token (dlouhý řetězec), které takto dostaneš, do souboru `token.txt`.
> [warning] Pozor!
-> Vygenerovaný kód je heslo, které držitele
+> Vygenerovaný token je heslo, které držitele
> opravňuje pracovat s Githubem pod tvým jménem!
> Drž ho v tajnosti. Kdyby se přece jen dostalo „ven”, na stránce
> [Personal Accesss Tokens](https://github.com/settings/tokens) ho deaktivuj.
-
+Obsah tokenu se ti zobrazí pouze jednou, hned po vytvoření.
+Když ho zapomeneš, deaktivuj ho a vytvoř si nový.
+
+
## Requests
K práci s internetovými stránkami použijeme knihovnu Requests.
@@ -87,10 +90,18 @@ print(stranka.text)
```
Co se stalo? Tím, že jsi Githubu dal{{a}} svůj token
-(načtený ze souboru, předaný přes slovník `headers`),
+(načtený ze souboru, předaný přes „přihlašovací“ slovník `headers`),
poznal, že jde dotaz od tebe a vrátil nějaké informace
ve formátu JSON.
+> [note]
+> Pokud kód opisuješ, pozor: v řetězci `'token '` je mezera.
+> „Přihlašovací“ slovník `headers` bude ve výsledku vypadat takto:
+>
+> ```python
+> {'Authorization': 'token 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'}
+> ```
+
Zkus řetězec `stranka.text` převést z JSON na slovník
a vypsat trochu srozumitelněji:
@@ -106,7 +117,7 @@ udržovat v tajnosti).
S profilem, který máš v proměnné `data`,
se dá pracovat jako s každým jiným slovníkem.
-Třeba adresu svého obrázku můžeš vypsat pomocí:
+Třeba adresu svého profilového obrázku můžeš vypsat pomocí:
```python
print(data['avatar_url'])
@@ -118,7 +129,7 @@ print(data['avatar_url'])
API Githubu toho umí mnohem víc. Třeba na adrese
[https://api.github.com/emojis](https://api.github.com/emojis) na tebe čeká
slovník s adresami malých obrázků.
-(Tenhle slovník funguje jako vyhledávací tabulka.)
+
Celé API je zdokumentováno na adrese
[developer.github.com](https://developer.github.com/v3/).
@@ -149,7 +160,7 @@ a `DELETE` něco maže.
Jakou metodu poujeme závisí na tom, co chceme udělat;
většinou to bude `POST`, `PUT` nebo `DELETE`.
-Podle [dokumentace Githubu](https://developer.github.com/v3/activity/starring/#star-a-repository)
+Podle [dokumentace Githubu](https://docs.github.com/en/rest/reference/activity#star-a-repository-for-the-authenticated-user)
se přidání hvězdičky dělá pomocí `PUT`
dotazu na adresu `/user/starred/:owner/:repo`.
Za `:owner` a `:repo`