C2184 Úvod do programování v Pythonu 10. Práce se soubory CSV a JSON Formát CSV • CSV = comma-separated values • Slouží pro ukládání tabulkových dat • Hodnoty jsou do sloupečků rozdělené pomocí separátoru {delimiter, většinou čárka) a do řádků pomocí znaku nového řádku • https://cs.wikipedia.org/wiki/CSV • Tabulka: Rok výroby Značka Model Cena 1995 Opel Vect ra 45 000 1998 Škoda Felicia 80 000 2002 Škoda Octavia 70 000 I_I_I_I_I • CSV: Rok výroby,Značka,Model,Cena 1995,Opel,Vect ra,45000 1998,Škoda,Felicia,80000 2002,Škoda,Octavia,70000 Modul csvv Pythonu • csv. reader - načítání formátu CSV • csv.writer - ukládání ve formátu CSV • https://docs.python.org/3/library/csv.html • csv. reader a csv.write se vytváří z již otevřeného souboru - Při otevírání souboru je nutné použít newline=' ', jinak se mohou vypisovat prázdné řádky navíc (zejména na Windows). 1 Čtení [1] [2] [3] with open('data/auta.csv', 'r', encoding='utf8') as f for line in f: # Klasické čtení bez CSV readeru print(line.rst rip('\n')) Rok výroby,Značka,Model,Cena 1995,Opel,Vect ra,45000 1998,Škoda,Felicia,80000 2002,Škoda,Octavia,70000 import csv from pathlib import Path with open('data/auta.csv', 'r', encoding='utf8', newline='') as f: reader = csv.reader(f) print(next(reader)) # Čte jeden řádek print('..........') for row in reader: # Čte postupně všechny řádky print(row) ['Rok výroby', 'Značka', 'Model', 'Cena'] ['1995', 'Opel', 'Vectra', '45000'] ['1998', 'Škoda', 'Felicia', '80000'] ['2002', 'Škoda', 'Octavia', '70000'] with open('data/auta.csv', 'r', encoding='utf8', newline='') as f: reader = csv.reader(f) table = list (reader) # Čte všechny řádky najednou -> seznam^ ^seznamů table [3]: [['Rok výroby', 'Značka', 'Model', 'Cena'], ['1995', 'Opel', 'Vectra', '45000'], ['1998', 'Škoda', 'Felicia', '80000'], ['2002', 'Škoda', 'Octavia', '70000']] • Načtené hodnoty jsou vždy řetězce, musíme šije sami převést na číslo • DictReader - z řádků dělá slovníky [4] : with open('data/auta.csv', encoding='utf8', newline='') as f: reader = csv DictReader(f, ['year', 'brand', 'model', 'price']) for row in reader: print(row) 2 {'year': 'Rok výroby', 'brand': 'Značka', 'model': 'Model', 'price':u VCena'} {'year': '1995', 'brand': 'Opel', 'model': 'Vectra', 'price': '45000'} {'year': '1998', 'brand': 'Škoda', 'model': 'Felicia', 'price':u ^'80000'} {'year': '2002', 'brand': 'Škoda', 'model': 'Octavia', 'price':u ^'70000'} • DictReader bez zadaných názvů sloupců - načte první řádek jako hlavičku with open('data/auta.csv', encoding='utf8', newline='') as f: reader = csv DictReader(f) for row in reader: print(row) {'Rok výroby '1995', 'Značka' : 'Opel', 'Model': ' Vect ra', 'Cena': ^'45000'} {'Rok výroby '1998', 'Značka' : 'Škoda' , 'Model': 'Felicia' , 'Cena':u ^'80000'} {'Rok výroby '2002', 'Značka' : 'Škoda' , 'Model': 'Octavia' , 'Cena':u ^'70000'} Zápis distances = [[ i Brno', 'Praha', 'Ost rava'], [ Brno', 0, 202, 165], [ Praha' , 202, 0, 362], [ Ost rava , 165, 362, 0]] with open('data/distances.csv', 'w', encoding='utf8', newline='') as : # Pozor na newline=' ' writer = csv.writer(f) writer.writerows(distances) print(Path('data/distances.csv').read_text(encodingsutf8')) ,Brno,Praha,Ost rava Brno,0,202,165 Praha,202,0,362 Ostrava,165,362,0 Zápis speciálních znaků • Tabulka: l-1-1-1-1-1 I Rok výroby I Značka I Model I Poznámka I Cena I 1995 Opel Vect ra klimatizace, střešni okno 45 000 1998 Škoda Felicia "Fun" 80 000 2002 Škoda Octavia klimatizace, ABS bou raná 70 000 I_I_I_I_I_I • CSV: 1995,Opel,Vectra,"klimatizace, střešni okno",45000 1998,Škoda,"Felicia ""Fun,,80000 2002,Škoda,Octavia,"klimatizace, ABS bouraná",70000 • A proto je modul csv tak užitečný. with open('data/auta2.csv', encoding='utf8', newline='') as r: reader = csv.reader(r) for row in reader: print(row) ['1995', 'Opel', 'Vectra', 'klimatizace, střešni okno', '45000'] ['1998', 'Škoda', 'Felicia "Fun"', '', '80000'] ['2002', 'Škoda', 'Octavia', 'klimatizace, ABS\nbouraná', '70000'] Parametry pro upřesnění formátu • delimiter - oddělovač sloupců (default ' , ') • quotechar - vyčlenění polí se speciálními znaky (default '"') • quoting - strategie použití quotecharu (povolené hodnoty csv. QU0TE_ALL, csv.QUOTE_MINIMAL, csv.QUOTE_NONNUMERIC, csv.QU0TE_N0NE) - Reader s quoting=csv. QUOTE_NONNUMERIC konvertuje na float vše, co není v uvozovkách. • doublequote - zdvojení quotecharu ruší jeho funkci (default True) • escapechar - ruší funkci speciálních znaků (delimiteru a quotecharu) (default None) • skipinitialspace - ignoruje mezery těsně za oddělovačem (default False) • dialect - nastavení více parametrů současně (např. ' excel') with open('data/distances.csv', 'w', encoding='utf8', newline='') asu : writer = csv.writer(f, delimiter^;', quoting=csv. ^QUOTE_NONNUMERIC) writer writerows(distances) [11]: print(Path('data/distances.csv') read_text(encodingsutf8')) "";"Brno";"Praha";"Ostrava" "Brno";0;202;165 "Praha";202;0;362 "Ostrava";165;362;0 [12] : with open('data/distances.csv', encoding= utf8', newlines') as f: for row in csv.reader(f, delimiters; , quoting=csv. ^QUOTE_NONNUMERIC): print(row) ['', 'Brno', 'Praha', 'Ostrava'] ['Brno', 0.0, 202.0, 165.0] ['Praha', 202.0, 0.0, 362.0] ['Ostrava', 165.0, 362.0, 0.0] Otázky: Jak musíme nastavit csv. reader, aby správně načetl tabulku? Wednesday:16 December:'18:00':'Ovečka Shaun ve filmu: Wednesday:16 December:'20:30':Story of Tantra Farmageddon' Thursday :17 December:'18:00' Thursday :17 December:'21:30' Friday :18 December:'18:00' Saturday :19 December:'20:30' Sunday :20 December:'20:30' Hungry Bear Tales Between the Seasons Disco in the Cinema Summer of 85 Klimt & Schiele - Eros and Psyche • A) csv.reader(f) • B) csv.reader(f, delimiters : • C) csv.reader(f, delimiters ; • D) csv. reader(f, delimiters; Formát JSON • JavaScript Object t\/otation escapechar=) quotechar=) 60 Kč 100 Kč 60 Kč 100 Kč 60 Kč 100 Kč 100 Kč quotechars"■; skipinitialspacesf rue) 5 • http://json.org/ • Ukázka: { "name": "John", "age": 35, "married": true, "cars": [ "Mercedes", "BMW", "Volkswagen" ] } • Mapování na typy Pythonu: Python JSON Poznámka int/float 5, 10.2 number 5, 10.2 string 'ahoj' string "ahoj" vždy dvojité uvozovky bool True, False boolean true, false None None null null list, tuple [], 0 array [] načte se vždy jako seznam diet {} object {} klíče musí být řetězce Modul j son • j son. load () - načti JSON ze souboru • j son .loads () - načti JSON z řetězce • j son. dump () - zapiš JSON do souboru • j son . dumps () - zapiš JSON do řetězce • https://does.python.org/3/library/j son.html Čtení [13]: with open('data/bob.json', encoding='utf8') as f: bob = f.read() # Načte řetězec bob [13]: '{\n "name": "Bob",\n "age": 30,\n "married": false,\n "cars": ^["Ford", "BMW", "Fiat"]\n}\n' [14]: import j son |with open('data/bob.json', encoding='utf8') as f: 6 bob = json.load(f) # Načte slovník bob [14]: {'name': 'Bob', 'age': 30, 'married': False, 'cars': ['Ford', 'BMW, V Fiat']} [15]: John = json.loads('{ "name": "John", "age": 35, "married": true, „cars„. ["Mercedes", "BMW", "Volkswagen"] }') John [15]: {'name': 'John', 'age': 35, 'married': True, 'cars': ['Mercedes', 'BMW, 'Volkswagen']} [16] Zápis alice = {'name': 'Alice', 'age': 28, 'married': False, 'cars' ^('Forď, 'Trabant')} [17]:Iwith open('data/alice.j son', 'w', encoding='utf8') as f: json.dump(alice, f) # Zapisuje do souboru [18] : print(Path('data/alice.j son').read_text(encodingsutf8')) {"name": "Alice", "age": 28, "married": false, "cars": ["Ford",, ^"Trabant"]} [19]: with open('data/alice.json', 'w', encoding='utf8') as f: json.dump(alice, f, indent=4) # Zapisuje do souboru, s odsazením^ ^4 [20] print(Path('data/alice.j son').read_text(encodingsutf8')) 'Alice", "age": 28, "married": false, "cars": [ "Ford", "Trabant" ] } [21] text = json.dumps(alice) # Nezapisuje do souboru, ale vrací řetězec text 7 [21]: '{"name": "Alice", "age": 28, "married": false, "cars": ["Ford",u ^"Trabant"]}' Otázky: Které z uvedených je validní JSON? • A) {ID: 12345, title: "Harry Potter and Learning Python", translations: ["en", "de", "cs", "sk", "hu", "pi"]} • B) {"ID": 12345, "title": "Harry Potter and Learning Python", "translations": ["en", "de", "cs", "sk", "hu", "pi"]} • C) {'ID': '12345', 'title': 'Harry Potter and Learning Python', 'translations': ['en', 'de', 'cs', 'sk', 'hu', 'pi']} • D) {"ID": "12345", "title": "Harry Potter and Learning Python", "translations": {"en", "de", "cs", "sk", "hu", "pi"}} Modul argparse • Předávání argumentů z příkazového řádku (CLI = Command Line Interface) • Stejný účel jako sys . argv, ale sofistikovanější a hezčí pro uživatele • https://does.python.org/3/library/argparse.html Argumenty z příkazového řádku (netýká se pouze Pythonu): • Poziční $ program argl arg2 • Volby/přepínsLČe/options/switchesl'flags - Modifikují chování programu - Začínají - (jednopísmenné) nebo - - (vícepísmenné) - Bez parametrů: $ program argl arg2 -s $ program argl arg2 --switch - S parametrem: $ program argl arg2 -o value $ program argl arg2 --option value • Různé kombinace: $ program --option value -s argl arg2 --switch 8 • Volba -h nebo - - help -> program nemá nic dělat, pouze vypsat nápovědu: $ program --help Načtení argumentů pomocí a rg par se 1. Vytvoříme parser 2. Přidáme parseru jednotlivé argumenty a volby 3. Načteme (zparsujeme) argumenty a volby pomocí parseru • Soubor pizza.py: from argparse import ArgumentParser def main() -> None: # Vytvoření parseru parser = ArgumentParser(description='Demo module for ordering pizza') # Poziční argumenty (povinné) parser.add_argument('address', help='Address for delivery', type=str) parser.add_argument('pizza', help='Type of pizza', choices=['Margherita', 'Funghi', '4Formaggi']) # Volba typu bool parser.add_argument('-x', '- - spicy', help='Extra spicy', action='store_true') # Volba typu str s výběrem parser.add_argument('-s', ' --size', help='Pizza size', choices=['small', 'medium', 'large'], default='medium') # Volba typu float parser.add_argument('-ť, '--tip', help='Tip for the delivery ($)', type=float, default=0.0) # Načtení argumentů a voleb pomocí parseru args = parser. parse_args () print('Address: ', args.address) print('Pizza type:', args.pizza) print('Size: ', args.size) print('Spicy: ', args.spicy) print('Tip: ', args.tip) if name == ' main ' : 9 main() • Spouštíme z příkazového řádku: $ python pizza.py $ python pizza.py --help $ python pizza.py 'Kamenice 5' Funghi $ python pizza.py 'Kamenice 5' 4Formaggi --size large --spicy --tip 1. $ python pizza.py 'Kamenice 5' 4Formaggi -s large -x -t 1.20 • (Uvozovkyjsou nutné u víceslovných argumentů, aby shell poznal, kde argument začíná a končí. Python už dostane řetězec bez uvozovek.) • Další možnosti add_argument: - nargs=' * ' - argument může mít libovolný počet hodnot (načtou se jako seznam) - nargs=' + ' - argument může mít libovolný počet hodnot, ale aspoň jednu (načtou se jako seznam) Přesměrování vstupu / výstupu • Příkazový řádek umožňuje přesměrovat výstup pomocí >, tj. standardní výstup programu (print) se nebude vypisovat na terminál, ale do souboru. Toto funguje na všechny programy, ne pouze Python. $ python --help > output.txt $ Is > output.txt • Pomocí I můžeme přesměrovat výstup programu do vstupu jiného programu: $ cat input_file.txt | python process_file.py > output_file.txt Další moduly - rozšiřující učivo Formát XML • Extensible Hlarkup Language • https://cs.wikipedia.org/wiki/Extensible_Markup_Language • Ukázka: Tove J ani Reminder Don't forget me this weekend! Jani 10 Tove Re: Reminder I will not Modul Ixml • Čtení a zápis ve formátu XML (https ://lxml .de) • Externí balíček, nutno doinstalovat pomocí pipu Modul pickle • https://does.python.org/3/library/pickle.html • Uložení pythonovských dat v binárním formátu • Dokáže uložit téměř libovolný objekt (např. i funkce) • Nebezpečí - pickle soubor z cizího zdroje může obsahovat škodlivý kód! Modul requests • https://pypi.org/proj ect/requests/ • Internetová komunikace přes protokol HTTP • Nutno doinstalovat pomocí pipu • Posíláme požadavek {request) na server pomocí metod GET, POST, PUT, DELETE... • Server nám vrací odpověď (response) [22]:I import requests URL = 'http://endless.horse' # URL = Uniform Resource Locator =u ^webová adresa response = requests.get(URL) # Používáme HTTP metodu GET print('STATUS:', response status_code) # Status code: 200 = OK, 404u Not Found... print('TEXT:', response.text[-700:]) # Posledních 700 znaků zeu ^stáhnutého textu STATUS: 200 TEXT: le="padding-top: 222px">
 , _,,)\.~,,■_ ((T ")\))),,_
I        \ "((\)))),,_
|6X     I     ' ' ((\())) "-.___.-
11
I    .'\    "))))' \))) I   I   x.     " ((((
\, _)        V |))))
I (((((
\ I ))))))
xI       I A /((((((
I     / x-.____.&U;   \     | )))))
11/ x. \   \ (((( I   / \ I W    | (((
\    I  I  I )l  I ))
I  I  I  I III '
Modul re • https://docs.python.org/3/library/re.html • Regulární výraz = regular expression = regex = RE • Způsob jak zapsat obecně vzorek textu, který chceme vyhledat/nahradit/... • Vzorek většinou zapisujeme jako raw-string (např. r' blabla'), abychom zrušili speciální význam \ pro Python - '\n' - jeden znak (nový řádek) - r' \n ' - dva znaky (\ a n) -> necháváme speciální význam pro RE [23]:|import re text = 'Helloooo! She sells sea shells. Good as hell!' re findall(r'[Hh]ello*', text) [23]: ['Helloooo', 'hell', 'hell'] [24]: re.findall(r'\b[Hh]ello+\b', text) [24]: ['Helloooo'] [25] : re.sub(r'\b[Hh]ello+\b', 'Ciao', text) [25]: 'Ciao! She sells sea shells. Good as hell!' [26]: re.findall(r'G.*!', text) 12 [26]: ['Good as hell!'] Vysvětlení [ Hh ] - jeden znak z výčtu (' H' nebo ' h ') o* - libovolný počet (včetně 0) opakování znaku o (' ' nebo ' o' nebo' oo'...) o+ - aspoň 1 opakování znaku o (' o' nebo' oo'...) . - libovolný znak . * - libovolný počet libovolných znaků \w = word characters = [a-zA-Z0-9_] \b - hranice slova Další možnosti použití: - https://docs.python.org/3.10/library/re.html - https://docs.python.org/3.10/howto/regex.html • Pozor, pravidla re a glob jsou jiná! Další příklady [27] : text = 'Tak se mějte hezky, já jdu žehlit a pokračoval v cestě.' re.findall(r'\w+', text) [27]: [ Tak' , se' , měj te', hezky', já', jdu', žehlit', a', pokračoval', V , cestě'] [28]: from pathlib import Path text = Path('data/no_side_effects.txt').read_text() re.findall(r"'(. + )" *- *( [0-9]{l,2} : [0-9]{2» ' , text) [28]: [('Poem', '6:23'), ('Flash', '5:24'), ('From Red to Rusk', '4:48'), ('Broken Pictures', '4:23'), 13 ('Shake-up', '8:10'), ('Trio Four', '4:36'), ('No Side Effects', '3:12'), ('Frame Three', '6:30'), ('Shag Bark Hickory', '2:25'), ("Leť s See", '3:57'), ('Ruddy', '4:20'), ('Vermilion', '4:12'), ('When the Winds Blow', '6:11'), ('Parched Plain', '13:38'), ('Shore Line', '5:22'), ('An Afternoon Walk', '6:02'), ('Enfold', '6:56'), ('Frame Two', '2:51'), ('They Danced', '3:35'), ('Ride', '3:41'), ('Here We Go', '3:39'), ('Rolling', '6:15'), ('Yellow Night', '6:41'), ('Sway', '2:53')] 14