Až potud jsme se o chybových zprávách příliš nezmiňovali, ale pokud jste si zkoušeli všechny příklady, určitě jste již nějaké viděli. Python rozlišuje dva různé druhy chyb - syntaktické chyby a výjimky. Následující kapitola proto bude věnována právě jim.
Syntaktické chyby, známé též jako chyby při parsování, jsou nejčastějším typem chyb, obzvláště pokud se Python teprve učíte:
>>> while 1 print 'Ahoj, světe' File "<stdin>", line 1, in ? while 1 print 'Ahoj, světe' ^ SyntaxError: invalid syntax
Parser zopakuje poslední řádek a vytiskne malou "šipku" ukazující na místo, kde byla chyba detekována. Chyba je způsobena (nebo přinejmenším detekována) tokenem před šipkou: v ukázce byla chyba detekována před klíčovým slovem print -- chybí před ním dvojtečka (":"). Vytištěno je také jméno souboru a číslo řádku, takže přesně víte, kde chybu hledat.
Přestože příkaz nebo výraz jsou syntakticky správně, mohou způsobit chybu při pokusu o jejich vykonání. Chyby zjištěné při běhu programu jsou nazývány výjimky a nemusí přímo vést k ukončení programu, program je totiž může odchytit a zajistit jejich nápravu. Pokud program nějakou výjimku neodchytí, interpretr vytiskne chybové hlášení podobné některému ze zde uvedených:
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: spam >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: illegal argument type for built-in operation
Poslední řádek chybového hlášení indikuje k jakému druhu chyby došlo. Je mnoho různých typů výjimek. Typ výjimky je vytištěn jako část zprávy, v uvedeném příkladě byly typy ZeroDivisionError, NameError a TypeError. Řetězec vytisknutý jako typ výjimky odpovídá jménu interní proměnné (to platí pro všechny interní výjimky, pro uživatelsky definované výjimky již ne). Jména standardních výjimek jsou internímy jmény (tedy ne vyhrazená klíčová slova jako v jiných jazycích).
Zbytek řádku je doplňující informace, jejíž interpretace závisí na typu výjimky, její význam se liší podle typu a kontextu výjimky.
Předcházející část chybové zprávy ukazuje kontext, kde k výjimce došlo (tj. výpis volaných funkcí). Většinou obsahuje i výpis jednotlivých řádek kódu, řádky načtené ze standardního vstupu se ale nezobrazují.
Dokument Python Library Reference detailně popisuje význam všech interních výjimek.
Každý program v jazyce Python může odchytit výjimky, které v jeho těle vzniknou. Podívejte se na následující příklad. Ten se dotazuje uživatele dokud ten nezadá platné celé číslo. Umožňuje ale uživateli přerušit program (použitím Control-C). Uživatelsky generované přerušení je signalizováno jako výjimka KeyboardInterrupt.
>>> while 1: ... try: ... x = int(raw_input("Zadejte celé číslo: ")) ... break ... except ValueError: ... print "Nebylo zadáno správně, zkuste to znovu..." ...
Konstrukce try pracuje následovně:
Konstrukce try může mít více než jednu větev except pro definování handlerů pro různé výjimky. Vždy může být ale spuštěn nejvýše jeden handler. Handlery mohou odchytit pouze výjimky, které vzniknou v odpovídajícím try bloku. Větev except může uvést více výjimek ve formě výčtu, například:
... except (RuntimeError, TypeError, NameError): ... pass
Poslední větev except může mít vynechán výčet výjimek - pak funguje jako žolík. Tuto možnost používejte velice opatrně, poněvadž takto můžete skrýt závažnou chybu v programu! Můžete jí třeba výhodně užít pro vytisknutí chybové zprávy a poté znovu vyvolat výjimku (což umožní volající funkci tuto výjimku obsloužit):
import string, sys try: f = open('myfile.txt') s = f.readline() i = int(string.strip(s)) except IOError, (errno, strerror): print "I/O error(%s): %s" % (errno, strerror) except ValueError: print "Nemohu převést data na celé číslo." except: print "Neznámá chyba:", sys.exc_info()[0] raise
Konstrukce try ...except má volitelnou větev else, která, je-li uvedena, musí být zapsána po všech větvích except. To je užitečné pro kód, který musí být spuštěn, nedojde-li k žádné výjimce. Například:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'nemohu otevřít', arg else: print arg, 'obsahuje', len(f.readlines()), 'řádků' f.close()
Vyskytne-li se výjimka, pak může mít přiřazenu hodnotu nazývanou argument výjimky. Přítomnost a typ argumentu se řídí typem výjimky. Pro ty typy výjimek, které mají argument, může větev except za jménem výjimky uvést proměnnou (nebo výčet), které bude přiřazena hodnota argumentu výjimky:
>>> try: ... spam() ... except NameError, x: ... print 'jméno', x, 'není definováno' ... jméno spam není definováno
Když má výjimka argument, je vytisknut jako poslední část ("detail") chybové zprávy pro neodchycené výjimky.
Handlery výjimek neobsluhují pouze výjimky, které se vyskytnou ve větvi try, ale také výjimky, které vzniknou uvnitř funkcí, které jsou uvnitř této větve volány. Například:
>>> def chyba(): ... x = 1/0 ... >>> try: ... chyba() ... except ZeroDivisionError, detail: ... print 'Běhová chyba:', detail ... Běhová chyba: integer division or modulo
Příkaz raise umožňuje programátorovi vyvolat určitou výjimku. Například:
>>> raise NameError, 'Ahoj' Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: Ahoj
První argument příkazu raise určuje jméno výjimky, která má být vyvolána. Volitelný druhý argument specifikuje argument výjimky.
Potřebujete-li zjistit, jestli se daná výjimka vyskytla, ale nechcete jí odchytit, pak použijte nejjednodušší tvar příkazu raise, který umožní vyvolat poslední výjimku, ke které došlo:
>>> try: ... raise NameError, 'Ahoj' ... except NameError: ... print 'Došlo k výjimce!' ... raise ... Došlo k výjimce! Traceback (most recent call last): File "<stdin>", line 2, in ? NameError: Ahoj
Programy mohou vytvořit svoje vlastní výjimky definováním nové třídy výjimek. Výjimky by měly být přímo či nepřímo odvozeny od třídy Exception, například:
>>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return `self.value` ... >>> try: ... raise MyError(2*2) ... except MyError, e: ... print 'Vyskytla se výjimka s hodnotou:', e.value ... Vyskytla se výjimka s hodnotou: 4 >>> raise MyError, 'oops!' Traceback (most recent call last): File "<stdin>", line 1, in ? __main__.MyError: 'oops!'
Třída vyjimky může být definován jako jakákoli jiná třída a může mít mnoho metod, ale většinou jsou navrženy jako jednoduché, většinou nabízející pouze několik atributů, které umožňují handlerům získat informace o této výjimce. Vytváříte-li modul, který může vyvolat hodně různých výjimek, často se vytvoří základní třída všech výjimek definovaných tímto modulem a odvozují se od ní nové třídy pro různé chybové stavy:
class Error(Exception): """Základní třída všech výjimek v tomto modulu.""" pass class InputError(Error): """Výjimky vyvolané pro chyby vstupu. Atributy: expression -- vstupní výraz, ve kterém došlo k chybě message -- popis chyby """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Vyvolána, když se program pokusí o nepovolenou změnu stavu modulu. Atributy: previous -- stav před změnou next -- nový stav message -- vysvětlení, proč daná změna není povolena """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message
Většina výjimek je definována pod jmény, které končí slovem "Error" - podobně jako standardní výjimky.
Mnoho standardních modulů definuje vlastní výjimky pro oznamování chyb, které se mohou vyskytnout v jejich funkcích. Více informací o třídách získáte v kapitole 9, "Třídy".
Konstrukce try má ještě jednu volitelnou větev, která je určena pro definování clean-up akcí (clean-up akce je kód, který musí být spuštěn za všech podmínek). Například:
>>> try: ... raise KeyboardInterrupt ... finally: ... print 'Mějte se, lidi!' ... Mějte se, lidi! Traceback (most recent call last): File "<stdin>", line 2, in ? KeyboardInterrupt
Větev finally je spuštěna za jakýchkoli okolností. Jestliže dojde k výjimce, je tato výjimka vyvolána až po vykonání větve finally. Větev finally je spuštěna také při opuštění bloku try (třeba pomocí příkazu return).
Kód ve větvi finally je užitečný pro uvolnění externích prostředků (jako souborů nebo síťových spojení) nezávisle na tom, zda prostředek byl nebo nebyl bezchybně použit.
Konstrukce try musí mít jednu nebo více except větví nebo jednu větev finally, nikdy ale ne obě zároveň.
See About this document... for information on suggesting changes.