C2184 Uvod do programování v Pythonu 10. Práce se soubory, moduly Práce se soubory Soubor • Sada dat uložených pod konkrétním jménem na datovém médiu • Např. f unny_cat. gif uložený v mých dokumentech • Každý soubor je uložen v nějakém formátu (JPEG, TXT, MPEG4,...) Základní rozdělení formátů • Textové (TXT, HTML...) - soubor tvořen posloupností znaků Vruboun posvátný (Scarabaeus sacer), označovaný také jen krátce skarabeus či skarab, je brouk z čeledi vrubounoviti (Scarabaeidae). Žije ve Středomoří. Samička naklade larvy do kuličky uhnětené z trusu, kterou posléze zahrabe do země. • Binární (ZIP, JPG, DOCX...) - soubor tvořen posloupností bajtů $$x$$E$$$D$L$/QlX$9l0r$m-[ô3$5$$$H$$$Dj+Y/$/$Da$D6$R$$$$/ Í4; Í41Í4 - nG; $$u$D$D$$M$2B$$$$#" $f " - *,[$$2Dapk$p$$$$/DD$)DV! <$D$$$6$DD$D$D#h | QblL^*^7& Poznámka: Textový soubor je vlastně binární soubor, kde každý bajt (skupina bajtů) kóduje nějaký znak. Rozdíl je v tom, jak budeme soubor číst. Základní operace se souborem • Otevření (open) • Čtení {read) • Zápis {write) • Zavření {close) = uložení změn na disk Otevření a zavření souboru v Pythonu • Explicitně - nedoporučuje se (hrozí, že zapomeneme soubor zavřít a změny se neuloží) In [30]: f = open('my_fil_e.txt1) # Pracujeme se souborem . . . # Pracujeme se souborem . . . f.close() • Pomocí bloku wit h - doporučený způsob (soubor se zavře automaticky na konci bloku) In [32]: with open(1my_file.txť) as f: # Pracujeme se souborem . . . # Pracujeme se souborem . . . # Tady se soubor automaticky zavře Funkce open • Argumenty: ■ Umístění souboru (path) ■ Můžeme upřesnit mód, kódovaní... • Návratová hodnota: ■ File object - popisuje, který soubor je otevřený, ukazatel na konkrétní místo v souboru, mód, kódování... with open(1 skarabeus.txť, mode='r', encoding=1utf81) as f: print(f) <_io.TextIOWrapper name=1 skarabeus.txť mode='r' encoding=1utf8'> Mód otevření textového souboru - čteme a zapisujeme znaky (st r) • 1 r1: pro čtení {read) - defaultní mód ■ soubor neexistuje-> FileNotFoundError ■ soubor existuje -> čte od začátku • 1 w': pro zápis (wr/te) ■ soubor neexistuje -> vytvoří ho ■ soubor existuje -> přemaže a zapisuje od začátku! • 1 x1: pro zápis ■ soubor neexistuje -> vytvoří ho ■ soubor existuje -> FileExistsError • 1 a1: pro zápis {append) ■ soubor neexistuje -> vytvoří ho ■ soubor existuje -> doplňuje na konec • 1 r+1 pro čtení a zápis ■ soubor neexistuje-> FileNotFoundException ■ soubor existuje -> čte/zapisuje od začátku • 'w+' pro čtení a zápis ■ soubor neexistuje -> vytvoří ho ■ soubor existuje -> přemaže a čte/zapisuje od začátku Ctení z textového souboru • Funguje pouze v módech r, r+,w+ • Metoda read přečte celý soubor (bez argumentu) nebo daný počet znaků (s argumentem) ■ Vrátí načtený řetězec • Po zavření souboru už nelze číst In [63]: with open(1 skarabeus.txť, mode='r') as f: text = f.read() text 0ut[63]: 'Vruboun posvátný (Scarabaeus sacer), označovaný také jen krátce skarabeus či skarab, je brouk z čeledi vrubounovití (Scarabaeidae). Žije ve Středomoří. Sam ička naklade larvy do kuličky uhnětené z trusu, kterou posléze zahrabe do zem ě. Vyvíjející se larva se živí trusem.\n1 In [67]: with open(1 skarabeus.txt1, mode='r') as f: prvnich_20_znaku = f.read(20) zbytek = f.read() prvnich_20_znaku 0ut[67]: 'Vruboun posvátný (Sc1 In [68]: zbytek 0ut[68]: 'arabaeus sacer), označovaný také jen krátce skarabeus či skarab, je brouk z č eledi vrubounovití (Scarabaeidae). Žije ve Středomoří. Samička naklade larvy d o kuličky uhnětené z trusu, kterou posléze zahrabe do země. Vyvíjející se larv a se živí trusem.\n' • Metoda readline načte jeden řádek ze souboru jako řetězec. • Pokud jsme už na konci souboru, vrátí se prázdný řetězec 1 1. In [52]: with open(1 nakup.txť, mode='r') as f: prvni = f.readlineO druhy = f.readlineO treti = f.readlineO ctvrty = f.readlineO In [53]: prvni 0ut[53]: 1 chleba\n1 In [54]: druhy 0ut[54]: 1 jogurt\n1 In [55] : treti 0ut[55]: '\n' In [56]: ctvrty 0ut[56]: • Řádek se načítá vždy se znakem nového řádku na konci. • Tohoto se zbavíme pomocí metody rst rip. In [71]: with open(1 nakup.txť, mode='r') as f: prvni = f.readline() i- In [72]: prvni I_ 0ut[72]: 'chleba\n' In [73]: prvni.rstrip() I_ 0ut[73]: 'chleba' • Metoda readlines načte všechny řádky (od aktuální pozice) jako seznam In [74]: with open(1 nakup.txť, mode='r') as f: radky = f.readlines() radky 0ut[74]: ['chleba\n\ 'jogurt\n', '\n'] v Ctení souboru pomocí for In [75]: with open(1 nakup.txť, mode='r') as f: for radek in f: print(radek) chleba jogurt Zápis do textového souboru • Funguje pouze v módech w, x, a, r+, w+ • Metoda write zapíše řetězec do souboru ■ Vrátí počet zapsaných znaků • Na konec se nevkládá automaticky nový řádek, jako u print • Po zavření souboru už nelze zapisovat In [123]: with open(1 novy.txť, mode='w') as f: f.write('Alice1) f.writer'Bob') f.writer1 Cyril1) In [124]: with open(1 novy.txť, mode='r') as f: text = f.read() text 0ut[124]: 1AliceBobCyril1 • Funkci p rint lze přesměrovat do souboru: In [125]: with open(1 novy.txť, mode='w') as f: print('Alice1, 10, True, file=f) In [126]: with open(1 novy.txt1, mode='r') as f: text = f.read() text 0ut[126]: 'Alice 10 True\n • Můžeme otevřít několik souborů současně In [119]: with open(1 nakup.txť, mode='r') as fr: with open(1 novy.txť, mode='w') as fw: for radek in fr: fw.write(radek.st rip()) fw.write(1;1) In [120]: with open(1 novy.txt1, mode='r') as f: text = f.read() text Out[120]: 'chleba;jogurt;; Metody tell a seek • Metoda tell vrací aktuální pozici ukazatele, seek nastavuje pozici ukazatele In [98]: with open(1 nakup.txť) as f: print(f .tellO) print(f.readline().rstrip()) print(f .tellO) print(f.readline().rstrip()) print(f .tellO) 0 chleba 7 jogurt 14 In [102]: with open(1 nakup.txt1) as f: f.seek(7) print(f.readline().rstrip()) jogurt Speciální "soubory" • sys . stdin - čte ze standardního vstupu • sys . stout - zapisuje na standardní výstup • sys . stderr - zapisuje na standardní chybový výstup Kódovaní souborů (encoding) • V souborech reálně nejsou uloženy znaky, ale pouze bajty • Kódování popisuje, jak se znaky zakódují do bajtů (encode) a zpátky {decode). • Příklady kódování: ■ UTF - 8 (ut f 8) - nejmodernější, dokáže zakódovat celou znakovou sadu Unicode (některé znaky se ukládají na více bajtů) ■ windows -1250 (cpl250) - středoevropské ■ windows -1252 (cpl252) - západoevropské Znaky ASCII (prvních 128 znaků z Unicode) se kódují stejně ve většině kódování • Príklad špatného rozkódování: In [104]: with open(1 skarabeus.txť, encoding = 1 windows-12501) as f: text = f.read() text Out[104]: 'Vruboun posvÄvtnÄ" (Scarabaeus sacer), oznaÄŤovanÄ" takÄ© jen krÄvtce skarabe us ÄŤi skarab, je brouk z ÄŤeledi vrubounovitÄ\xad (Scarabaeidae). Ľ'ije ve St L™edomoL™Ä\xad. SamiÄŤka naklade larvydo kuliÄŤky uhnÄ>tenÄ© z trusu, kterou poslÄ©ze zahrabe do zemÄ>. VyvÄ\xadjejÄ\xadcÄ\xad se larva se LľivÄ\xad truse m.\n 1 In [107]: with open(1 skarabeus.txt1, encoding = text = f.read() text UTF-8') as f Out[107] 'Vruboun posvátný (Scarabaeus sacer), označovaný také jen krátce skarabeus či skarab, je brouk z čeledi vrubounovití (Scarabaeidae). Žije ve Středomoří. Sam ička naklade larvy do kuličky uhnětené z trusu, kterou posléze zahrabe do zem ě. Vyvíjející se larva se živí trusem.\n1 • Defaultní kódování závisí na systému. In [106]: import locale locale.getpreferredencoding() Out[106]: 'UTF-8 Ukončování řádků • Unix (Linux a MacOS) ukončuje řádky jedním znakem '\n' • Windows ukončuje řádky dvojící znaků 1 \r\n 1 Na co si dát pozor • Kódování souborů • Řádky vždy končí bílými znaky (nejčastěji \n), proto je vhodné použití metod rstrip() nebo st rip() • Vždy musíte ukládat řetězec, vždy čtete řetězec • Pokud soubor zavřete, už s ním nemůžete dále pracovat (read, write); jedině že si ho znovu otevřete • Pokud soubor otvíráte v módu 1 w1, hrozí ztráta dat - současný soubor je ihned nenávratně přepsán novým prázdným souborem Binární soubory • Místo řetězců (st r) čteme a zapisujeme bajty (bytes). • Binární módy otevření: ' rb', ' wb', ' xb', ' ab', ' r+b', ' w+b'. • Metoda read vrací typ bytes. • Metoda write bere typ bytes. In [95]: with open(1 funny_cat.gif1, mode='r+b') as f: obsah = f.read(lQQ) obsah Out[95]■ blGIF89a\xe0\x01\xe0\x01\xf7\xff\x00\xll\r\x08\xl2\x0f\x0b\xl5\xl2\x0e\xla\xl2 \x0b\xla\xl5\x0f\xlb\xl8\xl4!\xlc\xl7#\xl2\x08#\xl9\x0f% \xl9(#\xlf)\xl8\r)\xl c\xl5,"\xl8.\1!2\xla\x0e4!\xl24$\xl95)!6/(7*\xla8."94+?%\xl9?,\xld?l\xle@l%A9. D2%' Moduly Modul (module) • Soubor funkcí a proměnných, které lze importovat In [131]: import math math 0ut[131]: In [133]: math.cos(O) 0ut[133]: 1-0 In [130]: math.pi Out[130]: 3.141592653589793 Balíček (package) • Modul obsahující další moduly (složka s moduly) 0ut[135]: In [138]: import os.path os.path 0ut[138]: Import pomocí f r om a a s • f rom - importujeme modul z balíčku nebo proměnnou (funkci) z modulu • a s - přejmenování importovaného modulu/proměnné/funkce In [139]: from os import path path I_ 0ut[139]: In [153]: import numpy as np np I_ 0ut[153]: In [145]: from math import factorial as fact fact(6) Out[145]: 720 Spuštění modulu jako skriptu • Z příkazové řádky pomocí přepínače - m: $ python3 -m doctest Zdroje modulu / balíčků • Standardní knihovna Pythonu ■ Moduly přítomné při instalaci ■ math, os, sys... ■ https://docs.python.Org/3.7/librarv/ (https://docs.pvthon.Org/3.7/librarv/) • PyPI - Python Package Index ■ Moduly doinstalovatelné např. pomocí nástoje pip ■ numpy, sklearn... ■ https://pypi.org/(https://pypi.org/) • Vlastní moduly ■ Každý pythonovský skript lze importovat jako modul Pip • Modul sloužící ke stáhnutí a doinstalování balíčků z PyPI • Spouštíme ho vždy z příkazové řádky pomocí - m (nesmí se importovat) $ python3 -m pip install numpy # Nainstaluj balíček numpy $ python3 -m pip show numpy # Vypiš verzi a info o nainstalovaném balíčku $ python3 -m pip search sound # Vyhledej balíčky související se zvukem $ python3 -m pip list # Vypiš seznam nainstalovaných balíčků $ python3 -m pip help # Vypiš nápovědu k pipu • V učebně A4/118 pip nefunguje (balíčky instaluje admin). Vlastní moduly • Máme dlouhý program -> můžeme ho rozdělit na více modulů ■ Z hlavního skriptu (_main_) pak importujeme ostatní moduly ■ Stejný modul lze importovat do více skriptů nebo do dalších modulů Soubor ukazkove_moduly/obsahy.py: d ii ii Modul pro výpočet obsahu různých geometrických útvarů, n n n import math def obsah_obdelniku(a: float, b:float) -> float: """Vrať obsah obdélníku o stranách a, b.""" return a * b def obsah_ctverce(a: float) -> float: """Vrať obsah čtverce o straně a. """ return a**2 def obsah_kruhu(r: float) -> float: """Vrať obsah kruhu o poloměru r. """ return math.pi * r**2 In [2]: from ukazkove_moduly import obsahy In [4]: obsahy.obsah_ctverce(5.0) 0ut[4]: 25.0 if name == 1 main • Tento blok se vykoná, pouze když modul spouštíme jako skript. • Když modul importujeme, tento blok se nevykoná. • (Toto funguje díky tomu, že pokud je modul importován, v magické proměnné _name_je název modulu; pokud je spouštěn jako skript, v proměnné _name_je 1_main_'.) Soubor ukazkove_moduly/fibonacci.py: Modul pro generování Fibonacciho posloupnosti. from typing import List def fib(n: int) -> Listfint]: """Vrat prvních n prvků Fibonacciho posloupnosti.""" result = [] a, b = 1, 1 while len(result) < n: result.append(a) a, b = b, a+b return result def main() -> None: """Interaktivní výpis Fibonacciho posloupnosti.""" počet = int(input(1 Zadej požadovaný počet prvků: ')) posloupnost = fib(pocet) print(*posloupnost, sep=', ') if__name_ == 1_main_1 : main() Import: In [2] : from ukazkovemoduly import fibonacci as fib In [8]: fib.fib(lO) 0ut[8]: [If 1» 2> 3, 5, 8, 13, 21, 34, 55] • Spuštění z příkazové řádky: $ python3 ukazkove_moduly/fibonacci.py Zadej požadovaný počet prvků: 10 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 Užitečné moduly Standardní knihovna: https://docs.python.Org/3.7/librarv/ (https://docs.python.Org/3.7/librarv/) Python Package Index: https://pypi.org/ (https://pypi.org/) Následující slajdy Modul math • Matematické funkce Modul cmath • Matematické funkce nad komplexními čísly Modul random • Generování pseudo-náhodných čísel In [19]: import random random.random() # Náhodné reálné číslo z intervalu [0, 1) 0ut[19]: 0-02197556072011697 In [20]: random.randint(0, 100) # Náhodné celé číslo z intervalu [0, 100] Out[20]: 7 In [22]: random.choice([1 červená 1, 'zelená1, 'modrá1, 'černá']) # Náhodný výběr 0ut[22]: 'červená' Modul datetime • Práce s časovými údaji • Základní typy: ■ datetime - datum + čas ■ timedelta - trvání ■ date-datum ■ time-čas ■ timezone - časová zóna In [35]: from datetime import datetime, timedelta začátek = datetime.now() math.factorial(1000000) konec = datetime.now() delka_vypoctu = konec - začátek print(delka_vypoctu) 0:00:05.916388 In [36]: dnes = datetime.now().date() za_tyden = dnes + timedelta(weeks=l) print(dnes) print(za_tyden) 2019-11-18 2019-11-25 In [37] 0ut[37] za_tyden.strftime('%A, %d. %B%Y') 'Monday, 25. November 2019' In [7] : from datetime import datetime datetime.strptime('1. 7. 2000, 13:30:05', '%d sm %Y, %H:%M:%S') 0ut[7]: datetime.datetime(2000, 7, 1, 13, 30, 5) Modul itertools • Různé možnosti iterování In [38]: import itertools for dvojice in itertools.combinations([1 bílá1, 'zelená1, 'modrá', 'černá'], 2): print(*dvojice) bílá zelená bílá modrá bílá černá zelená modrá zelená černá modrá černá In [31]: for pismeno, cislo in itertools.zip_longest('ABCDE', [1, 2, 3], fillvalue='?'): print(pismeno, cislo) A 1 B 2 C 3 D ? E ? Modul sys • Funkce závislé na systému In [30]: import sys sys.version # Verze interpretru Out[30]: '3.6.8 (default, Oct 7 2019, 12:59:55) \n[GCC 8.3.0] • sys . a rgv - seznam argumentů z příkazové řádky ■ Nultý argument = název skriptu Soubor ukazkove_moduly/suma. py: import sys print(sys.argv) suma = sum(int(x) for x in sys.argvfl:]) print(suma) • Spustíme z příkazové řádky: $ python3 ukazkove_moduly/suma.py 15 8 [1 suma.py1, 111, 151, 181] 14 Modul os • Funkce závislé na operačním systému ■ os . getcwd () - zjisti aktuálni pracovní adresář ■ os . chdir () - změň pracovní adresář ■ os.listdirO - vráť obsah adresáře ■ os . mkdir()-vytvoř nový adresář ■ os . makedirs () - vytvoř nový adresář, včetně všech nadadresářů ■ os . rename () - přejmenuj soubor nebo adresář ■ os. remove ()-smaž soubor ■ os . rmdir()-smaž prázdný adresář In [32]: import os os.getcwd() 0ut[32]: Vhome/adam/School/Praca/Python/2019/Prezentace1 In [33]: os.chdir(1ukazkovejnoduly1) os.getcwd() Out[33]: '/home/adam/School/Praca/Python/2019/Prezentace/ukazkove_moduly1 In [41]: os.chdir(1..1) # Dvě tečky označují nadadresář os.getcwd() Out[41]: '/home/adam/School/Praca/Python/2019/Prezentace1 i In [36]: os.listdir(1ukazkove_moduly1) 0ut[36]: [1fibonacci.py1, 1_pycache__', 'obsahy.py1, 'suma.py'] In [25]: os.makedirs(1ukazkove_moduly/novy/novy_podadresar1) Modul shutil • Více možností než os In [27]: import shutil shutil.rmtree(1ukazkove_moduly/novy1) # Smaž adresár nový a všechno v něm In [ ] : shutil.copy(1Pictures/funny_cat.gif1, 'Desktop/CLICK_HERE.gif1) # Zkopíruj soub IfL_I_ "_ In [ ]: shutil.copytree(1 Pictures 1, 1Desktop/Studijni_materialy_z_Pythonu1) # Zkopíruj adresář a všechno v něm Modul os.path • Funkce pro práci s cestami {path = umístění souboru nebo adresáře) • Řeší za nás rozdíly mezi operačními systémy • Absolutní cesta - začíná v kořeni souborového systému (v Unixu /, ve Windowsu písmeno disku): /home/krtecek/Pictures/funny_cat.gif C:\Users\Krtecek\Pictures\funny_cat.gif • Relativní cesta - začíná v aktuálním adresáři (., nemusí se psát): Pietures/funny_cat.gif ./Pietures/funny_cat.gif Pietures\funny_cat.gif .\Pictures\funny_cat.gif Modul os.path • os . path . j oin () - spojení částí cesty In [1] : from os import path path.join('Pictures', 'funny_cat.png') Out[l]: 'Pictures/funny_cat.png' In [9]: path.abspath('Pictures/funny_cat.png') Out[9]: '/home/adam/Pictures/funny_cat.png' In [10]: path.dirname('/home/adam/Pictures/funny_cat.png') I_._ 0ut[10]: '/home/adam/Pictures' In [11]: path.basename('/home/adam/Pictures/funny cat.png') L_ _ _ _ Out[ll]: 'funny_cat.png' I- In [2]: path.exists(1/home/adam/Pictures/funny_cat.png1) l_ 0ut[2]: False In [3]: path.isfile(1/home/adam/Pictures/funny_cat.png1) I_._ 0ut[3]: False In [4]: path.isdir(1/home/adam/Pictures/funny_cat.png1) 0ut[4]: Fa_Lse Zkoušíme otevřít soubor • Ask for forgiveness, not for permission. • Nezjišťujeme, jestli soubor existuje a lze ho otevřít Prostě ho zkusíme otevřít. In [28]: try: with open(1 neexistujici_soubor.txt1) as f: print(f.read()) except FileNotFoundError: print(1 Soubor neexistuje.1) except PermissionError: print('Nemáš právo číst soubor.') except OSError: print('Soubor se nepodařilo otevřít.') Soubor neexistuje. Modul glob • Chytrý výpis souborů v adresáři pomocí funkce glob. glob () ■ * - libovolný počet znaků (tj. i 0 znaků) ■ **-všechny soubory včetně podúrovní (pokud recursive=True) ■ ? -jeden libovolný znak ■ [A-Za-z] - jeden znak z výčtu In [6]: import glob glob.glob(1 Pietures/*1) Out[6]: ['Pietures/funny_cat.gif1, 1 Pietures/funny_dog.gif1, 1 Pictures/grumpy_cat.gif1, 1Pictures/giraffes1] In [20]: glob.glob(1Pictures/funny_*.gif1) Out[20]: ['Pictures/funny_cat.gif1, 1Pictures/funny_dog.gif1] In [19]: glob.glob(1 Pictures/**1, recursive=True) 0ut[19]: ['Pictures/', 1 Pictures/funny_cat.gif1, 1Pictures/funny_dog.gif1, 1Pictures/grumpy_cat.gif1, 1 Pictures/giraffes 1, 1Pictures/giraffes/mad_giraffe.gif1, 1Pictures/giraffes/sad_giraffe.gif1, 1Pictures/giraffes/confused_giraffe.gif1] In [22]: glob.glob(1Pictures/giraffes/?ad_giraffe.* 1) 0ut[22]: ['Pictures/giraffes/mad_giraffe.gif1, 1Pictures/giraffes/sad_giraffe.gif1] In [24]: glob.glob(1 Pictures/funny [bcr]at.gif1) I___ Out[24]: ['Pictures/funny_cat.gif1] Další užitečné moduly argparse requests subprocess json CSV pickle email re codecs warnings numpy matplotlib sklearn pandas