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`