Výjimky. Práce se soubory. Výjimky. Hiearchie výjimek. Práce se soubory. Textový režim. Binární režim. Serializace. Tomáš Bayer bayertom@natur.cuni.cz Katedra aplikované geoinformatiky a kartografie, Přírodovědecká fakulta UK. 1 / 37
Obsah přednášky 1 Výjimky 2 Práce se soubory 3 Textové soubory 4 Binární soubory 5 Serializace 2 / 37
Výjimky 1. Výjimky Ošetření chyb, ke kterým dochází za běhu programu (runtime). Neřeší syntaktické chyby. Příklady: chyby vstupu, výstupu, chyby aritmetických operací. Pokud neošetříme, dojde k pádu aplikace ztráta dat Varianty reakce na chybu : 1 Ukončení běhu programu Nepředvídatelnost vzhledem ke vstupu, ztráta dat. 2 Ošetření všech singularit Snaha ošetřit všechny možné chybové stavy. Prakticky nemožné, nepřehledný kód. 3 Použití vyjímek Odchycení a ošetření skupin chyb jednotně. Často se kombinují metody 2), 3). Mechanismus práce s výjimkami podobný pro většinu jazyků. 3 / 37
2. Syntaktická vs. run-time chyba Syntaktická chyba: >>> primt("hello world") Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'primt' is not defined Run-time (běhová) chyba: Odmocnina ze záporného čísla >>> sqrt(-1) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: math domain error Dělení nulou >>> 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero Chyba konverze >>> a = int(input("input value:")) Input value:r Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'r'
Výjimky 3. Výjimka (Exception) Stav programu v okamžiku, kdy dojde při jeho vykonávání k chybě. Vytvořen objekt, který nese informaci o typu chyby. Upozornění na výjimku chybovým hlášením. Všechny výjimky potomkem třídy BaseExceptions. Specifické výjimky pro různé typy chyb. Nejčastější použití: aritmetické chyby, překročení indexu, práce se soubory, konverze. 5 / 37
Výjimky 4. Ošetření výjimek Výjimky lze ošetřit 3 způsoby: 1 Propagace výjimky: Výjimka není ošetřena v metodě, ve které vznikla. Je předána do nadřazené úrovně. 2 Chráněné bloky: Výjimka je ošetřena v metodě, ve které vznikla. Na vyšších úrovních neřešeno. 3 Kombinace 1) a 2): Výjimka (částečně) ošetřena v místě, kde vznikla. Dále předána do nadřazené úrovně. Používáno nejčastěji. Umožňuje komplexní obsloužení výjimky. 6 / 37
Výjimky 5. Propagace výjimky Výjimka není ošetřena v místě, kde vznikla. Její zpracování předáváme do nadřízené úrovně. Hierarchie předávání metoda->main->python Použito např. v cyklu, nechceme opakovaně chybu řešit v těle. Při prvním výskytu výjimky ji předáme výše dořešení. Není -li dořešena v main(), ukončení programu. Příkaz raise raise exception(args) raise exception raise Nepoužívat generický typ, ale co nejkonkrétnější. 7 / 37
Výjimky 6. Ukázka propagace výjimky Výpočet poloměru kružnice při známém obvodu. Propagace do main() Volání: def getr(p): if p > 0: return p / (2 * pi) else raise ValueError(Perimeter < 0:, p) >>> print(getr(1)) 0.15915494309189535 Pokud v main() neošetřeno, pád programu: >>> print(getr(-1)) #Neosetrena vyjimka File "...exceptions.py", line 20, in <module> main() File "...exceptions.py", line 15, in main print(getr(-1)) 8 / 37
Výjimky 7. Ošetření metodou chráněných bloků Ošetření výjimky v místě, kde vznikla. Konstrukce try-catch, v Pythonu try-except. Chráněný blok try() obsahuje nebezpečný kód. try: blok prikazu except vyjimka_1: blok prikazu... except vyjimka_n: blok prikazu else: blok prikazu finally: blok prikazu Blok except(), ošetření konkrétního typu výjimky. Blok else(), volitelný, provede se, pokud try() úspěšný. Blok finally(), volitelný, provede se vždy. 9 / 37
Výjimky 8. Ukázka try-except 10 / 37
Výjimky 9. Ukázka chráněného bloku def f (x): try: return sqrt(x[0]/x[1]) except ZeroDivisionError: return -1 #Chybovy kod, deleni nulou except ValueError: return -2 #Chybovy kod, numericka chyba except IndexError: return -3 #Chybovy kod, spatny index except Exception: return -4 #Nespecifikovana chyba else: Volání funkce: x = [1, 2, 7] r = f(x) print("ok results") 11 / 37
Výjimky 10. Zásady práce s výjimkami Nepoužívat prázdné bloky except() řádná reakce na chybu. Odchycení obecné chyby: společný předchůdce, třída Exception. Odchycení více vyjímek: řazení dle dědické hierarchie: except Predek:... except Nejaky_rodic:... except Nejaky_rodic_rodice:... Čím obecnější, tím níže v except() bloku. Odchycení informací o výjimce do proměnné except ValueError as e: Vytištění informace o výjimce: při odlad ování programu except ValueError as e: print(e) 12 / 37
Výjimky 11. Kombinace chráněných bloků a propagace Kombinace předchozích postupů. Umožňuje výjimku ošetřit v místě, kde vznikla a ji předat výše. Na výjimku lze reagovat opakovaně na různých úrovních programu. V praxi nejpoužívanější metoda, zvláště u komplikovaných SW. def f (x): try: return sqrt(x[0]/x[1]) except ZeroDivisionError as e: raise e except ValueError as e: raise e except IndexError as e: raise e except Exception as e: raise e 13 / 37
Výjimky 12. Kombinace chráněných bloků a propagace Spojení aritmetických vyjímek do nadřazené. Použití ArtihmeticError: společný předek. Společná reakce na špatná vstupní data. def main(): x = [1,2] try: r = f(x) except ArithmeticError: #Vsechny aritmeticke chyby print(bad data) exceptindexerror: #Index pole print(list contains less than 2 elements) 14 / 37
Výjimky 13. Vlastní výjimky Lze vytvářet vlastní třídy výjimek odvozených od Exception. Možnost ošetření stavů, které nelze odchytit běžnými výjimkami. Volání: class FactorialError(Exception): def init (self, value, message): self.value = value self.message = message def f(n): if abs(n) > 100: raise FactorialError(n, Factorial, n>100) if n > 1: return n * f(n-1) else: return 1 15 / 37
14. Práce se soubory Práce se soubory Soubory - načítání/ukládání dat vytvořených SW. Python 3 podporuje široké spektrum operací se soubory. Typy souborů: textové, binární, HTML, XML, JSON. Podpora ZIP komprese/dekomprese. Velké množství externích knihoven: práce s rastry, shape fily... Základní operace: Otevření, čtení, zápis, uzavření, komprese, dekomprese. serializace. Soubor reprezentován streamem (proudem). Manipulace se soubory v try-except bloku: IOError. 16 / 37
15. Textový soubor Práce se soubory Představován posloupností řádek. Každá řádka tvořena posloupností znaků. Konec řádky, zkratka EOL (různý pro různé OS), vyjádřen \n CR + LF LF CR WinX GNU/Linux MacOS Unicode: LF (0x0A), CR(0x0d) Čitelný, lze snadno editovat. Ukázka: 105 723304.23 1023067.98 208.37 106 723297.17 1023071.04 206.92 106 723301.55 1023068.64 207.76 17 / 37
Práce se soubory 16. Binární soubor Tvořen posloupností bytů zapsaných v hexadecimální soustavě. Ne vše lze uložit jako text. Souvislý blok dat, není dělen na řádky, slova. Není přímo čitelný bez znalosti formátu. Záhlaví představováno headerem (hlavičkou) s popisem formátu (nepovinné). Následuje vlastní datová oblast. Používán např. pro spustitelné soubory (exe, bin). Ukládání rastrových dat, hudby, videa, dokumentů. Ukázka: ' AÁ~ S 64'ÁôýÔX/0Áj ôóš&á Î7Kr/Á @ F ó}ö!'ázd;»v /Álç{!'Ááz v/á F ó}ö!'áház v/á " Ä!'Ááz v/álç {!'Á%Uv/Á# >!'ÁZd;»v/ÁF ó}ö!'áház v/á @ rh`!' Áo ÿv/ávm!'á±ä 0Çv/Á rh`!'á333ó v/á-!'á±ä 0Çv/ ÁVm!'ÁÖŠp Öv/Á Ä`!'Áo ÿv/á rh`!'á333ó v/á @ Zd!'Á óýt\w/áé&1!'ávbw/á Zd!'Á` ÐâJw/ÁT!'ÁVBw/ Áé&1!'Áé&1ƒSw/ÁDlg!'Á óýt\w /ÁZd!'Á` ÐâJw/Á @ Ä 18 / 37
17. Otevření souboru Práce se soubory Soubor lze otevřít v několika módech file_object = open(file_name, mode) V cestě nepoužita zpětná lomítka: E:/Data/my_file.txt Přehled módů: Označení Mód Popis r Read Otevření souboru pro čtení (read only). w Write Otevření souboru pro zápis, původní obsah přepsán. a Append Otevření souboru pro zápis, přidání nových dat na konec r+ Read/Write Kombinace čtení i zápisu. t Text Otevření v textovém režimu (default) b Binary Otevření v binárním režimu. 19 / 37
Práce se soubory 18. Ukázka otevření souboru Otevření v try-except bloku: import os def tiletest(file): try: open(file, "r") result 1 except IOError: print ("Error: File does not exist.") result 0 finally: close(file) return result Volání funkce: result = FileCheck("test.txt") print (result) 20 / 37
19. Vlastnosti proudu Práce se soubory Existuje mnoho nástrojů, které lze zjistiti stav streamu: file = open(test.txt, "r") Název souboru/proudu: file.name Dotaz, zda je proud otevřený/zavřený: file.close Dotaz na mód: file.mode Lze z něj číst? file.mode Lze do něj zapisovat? file.writable Tomáš Uzavření Bayer bayertom@natur.cuni.cz proudu: velmi (Katedra důležitá aplikované Výjimky. geoinformatiky funkce. Práce se soubory. a kartografie, Přírodovědecká fakulta UK.) 21 / 37
Práce se soubory 20. Příkaz with Jednodušší syntaxe než s využití try-except-finally. Lze použít pro čtení i zápis. Provádí automatické uzavření souboru i v případě výjimky. Ve většině případů doporučováno jako výchozí metoda. with open(file_name) as file_object: do_something Ukázka otevření souboru: with open(file_name) as file_object: data = file.read() Následně není nutné řešit close(). 22 / 37
Textové soubory 20. Čtení z textového souboru 3 základní varianty: 1 Načtení celého souboru Načtení celého souboru najednou do proměnné typu String. file_content = file.read() 2 Čtení po řádcích Načte s každým zavoláním další řádku souboru, String file_line = file.readline() 3 Načtení souboru po řádcích Subor načten jednorázově, po řádcích. Výsledek seznam Stringů. file_line = file.readlines() 4 Čtení předem specifikovaného počtu znaků Načtení předem daného množství n znaků do Stringu. file_part = file.read(n) 23 / 37
21. Ukázka načtení souboru po řádkách Varianta 1: Varianta 2: Varianta 3: Varianta 4: Varianta 5: with open(test.txt, r) as f: for l in f.readlines(): print(l) for l in f: print(l) l = f.readline() while l: print(l) l = f.readline() print(f.read().split("\n")) print(f.readlines())
Textové soubory 22. Problém s EOL Na konci řádky EOL: Monday \n Tuesday \n Wednesday \n... Odstranění white spaces: for l in f: print(l.strip()) Alternativně: f.read().splitlines() 25 / 37
23. Pohyb v oteřeném streamu Zjištění pozice ve streamu v bytech: tell() #Nabyva hodnot <0, n-1> Posun na aktuální pozici v souboru v bytech: Módy: seek(position, mode) Mód Vyjádření Popis 0 os.seek_set Posun na začátek souboru. 1 os.seek_cur Posun na aktuální pozice. 2 os.seek_end Posun na konec souboru. Ukázka použití: skok na konkrétní řádku. Pamatujeme si délky řádek, ukládáme do seznamu. Pak: begins = [] begin = 0 for l in f: begins.append(begin) begin = begin + len(l) f.seek(begins[k]) #Skok na k-tou radku
24. Zápis do souboru Textové soubory Do oteřeného proudu lze zapisovat. V režimu w původní obsah souboru nahrazen. V režimu a připisujeme na konec souboru. Po skončení zápisu soubor nutno uzavřít. Zapisování po řádcích: využití \n write(string) Ukázka line = Friday\n file = open(test.txt,a) file.write(line) file.close #Pridani dat na konec souboru 27 / 37
Binární soubory 25. Čtení z binárního souboru Binární soubory mohou obsahovat různá data (obrazová, dokumenty,...). Soubory načítáme po bytech (1B!= 1 znak). Nutno nastavit mód b (binary). f = open(picture.jpg, rb) file_content = f.read() #Nacteni celeho souboru file_content = f.read(n) #Nacteni n bytu f.seek(2) #Skok na konec souboru length = f.tell() #Zjisteni delky souboru f.seek(0) #Skok na pocatek souboru\ Bez externích knihoven bude rastr interpretován jako proud bajtů. Pro další práci nutné knihovny. 28 / 37
Binární soubory 26. Zápis do binárního souboru Zápis dat do souboru po bytech. Vyjádřeny jako hexadecimální řetězce: znaky 0-9, A-F. Prefix každého bajtu \x. f.write(b\xa0\xa1\xa2\xa3) #Zapis 4 bytu V Pythonu 3 datový typ bytearray Pak: b = [160, 161, 162, 163] ba = bytearray(b) f2.write(ba) f2.close() >>> print(ba) bytearray(b'\xa0\xa1\xa2\xa3') 29 / 37
Serializace 27. Serializace Uložení/načtení obsahu datových struktur do/z souboru. Soubory (textové, binární) odevírat v módech rb/r a wb/w. Data mohou být použita při dalším spuštnění. Využití pro ladění programů. Nevýhoda: obtížná editace obsahu (binární soubory). Podpora serializace pro: Základní datové typy. Dynamické datové struktury. Funkce. Třídy. Modul pickle: 4 verze protokolů, vzájemná nekompatabilita. 30 / 37
Serializace 27. Serializace a deserializace pickle, ukázka Uložení do souboru: metoda dump(data_object, file) import pickle d = {'name' : 'John', 'surname': 'Smith', 'job': 'cartographer', 'age' : '25'} with open('test.pickle', 'wb') as f: pickle.dump(d, f) Ukázka souboru test.pickle: }q (X nameqx JohnqX ageqx 25qX jobqx cartographerqx surnameqx Smithqu. Načtení ze souboru: metoda load(data_object, file) with open('test.pickle', 'rb') as f: d2 = pickle.load(f) 31 / 37
Serializace 28. Serializace s využitím JSON Uložení/načtení do formátu JSON. JSON: Java Script Object Notation. Univerzální formát pro serializaci objektů. Výhodou textová struktura, snadno lze editovat. Existuje i jeho prostorová varianta: GeoJSON. Jedna z možností vstupu prostorových dat do Pythonu. Podpora serializace/deserializace pro stejné typy jako u Pickle. Uložení a načtení, metody dump() a load(). Soubory otevřeny v režimech r, w. 32 / 37
Serializace 29. Serializace a deserializace JSON, ukázka Uložení do souboru: metoda dump(data_object, file) import json d = {'name' : 'John', 'surname': 'Smith', 'job': 'cartographer', 'age' : '25'} with open('test.json', 'w') as f: json.dump(d, f) Ukázka souboru test.json: {"age": "25", "surname": "Smith", "job": "cartographer", "name": "John"} Načtení ze souboru: metoda load(data_object, file) with open('test.json', 'rb') as f: d2 = json.load(f) 33 / 37
Serializace 30. GeoJSON Formát pro výměnu prostorových dat založený na JavaScriptu (2008). Textová formát, snadná čitelnost, univerzalita. Používán často pro webové mapování. Nevýhodou neefektivita popisu, vhodný pro menší data. Ukládá pouze geometrická data, atributová nikoliv. Založen na sytému WGS-84, jednotky: stupně. Podpora entit dle OGIS (7): Point, LineString, Polygon + multi varianty. Detailní specifikace formátu: http://geojson.org/ 34 / 37
31. Podpora GeoJSON v Pythonu 3 Python 3 podporuje práci s formátem GeoJSON. Instalace: pip install geojson Ukázka struktury GeoJSON: kompozice Feature Objects { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [ [ 14.425022006034853, 50.06900389174371 ], [ 14.423967897891997, 50.06875597855528 ] ] } } ] }
Serializace 32. Serializace a deserializace GeoJSON, ukázka Načtení ze souboru: metoda load(data_object, file) import geojson with open('test.geojson') as f: d = geojson.load(f) Výpis entit: Uloženy ve slovníku, klíč features. Každá feature tvořena slovníkem, klíč geometry. for f in d['features']: print f['geometry']['type'] print f['geometry']['coordinates'] Uložení do souboru: metoda dump(data_object, file) with open('test2.geojson', 'w') as f: geojson.dump(d, f) 36 / 37
33. Znázornění GeoJSON