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:
, _,,)\.~,,■_ ((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 '