11# Výjimky
22
3- O [ chybových výpisech] ({{ lesson_url('beginners/print') }}) už v tomto
4- kurzu byla zmínka: Python si postěžuje, řekne, kde je chyba, a ukončí program.
5- O chybách se toho ale dá říct mnohem víc.
3+ Pojďme si prohloubit znalosti o chybách, neboli odborně o * výjimkách*
4+ (angl. * exceptions* ).
65
7-
8- ## Výpisy chyb
9-
10- Na začátku si ukážeme (nebo zopakujeme), jak Python vypíše chybu, která
11- nastane v zanořené funkci:
6+ Vezmi následující funkci:
127
138``` python
14- def vnejsi_funkce ():
15- return vnitrni_funkce(0 )
16-
17- def vnitrni_funkce (delitel ):
18- return 1 / delitel
19-
20- print (vnejsi_funkce())
9+ def nacti_cislo ():
10+ odpoved = input (' Zadej číslo: ' )
11+ return int (odpoved)
2112```
2213
23- <!-- XXX: Highlight the line numbers -->
14+ Když uživatel nezadá číslice, ale třeba text ` cokolada ` ,
15+ nastane výjimka jménem ` ValueError ` (chyba hodnoty) a Python vypíše
16+ odpovídající chybovou hlášku.
2417
2518``` pycon
26- Traceback (most recent call last):
27- File "/tmp/ukazka.py", line 7, in <module>
28- print(vnejsi_funkce())
29- File "/tmp/ukazka.py", line 2, in vnejsi_funkce
30- return vnitrni_funkce(0)
31- File "/tmp/ukazka.py", line 5, in vnitrni_funkce
32- return 1 / delitel
33- ZeroDivisionError: division by zero
19+ Traceback (most recent call last):
20+ File "ukazka.py", line 3, in nacti_cislo
21+ cislo = int(odpoved)
22+ ValueError: invalid literal for int() with base 10: 'cokolada'
3423```
3524
36- Všimni si, že každá funkce, jejíž volání vedlo k chybě, je uvedena ve výpisu.
37- Skutečná chyba (tedy místo, které musíme opravit)
38- je pravděpodobně poblíž některého z těchto volání.
39- V našem případě bychom asi neměl{{gnd('i', 'y', both='i')}} volat
40- ` vnitrni_funkce ` s argumentem ` 0 ` .
41- A nebo by ` vnitrni_funkce ` měla být na nulu
42- připravená a dělat v tomto případě něco jiného.
25+ Program volá funkci ` int() ` pro něco, co nedává smysl jako číslo.
26+ Co s tím má chudák funkce ` int ` dělat?
27+ Není žádná rozumná hodnota, kterou by mohla vrátit.
28+ Převádění tohoto textu na celé číslo nedává smysl.
4329
44- Python nemůže vědět, na kterém místě by se chyba měla opravit, a tak ukáže vše.
45- Ve složitějších programech se to bude hodit.
30+ Až funkce ` nacti_cislo ` nejlíp „ví“, co se má stát, když uživatel nezadá
31+ číslice.
32+ Stačí se uživatele zeptat znovu!
33+ Kdybys měl{{a}} funkci, která zjistí jestli jsou v řetězci jen číslice,
34+ mohlo by to fungovat nějak takhle:
4635
36+ ``` python
37+ def nacti_cislo ():
38+ while True :
39+ odpoved = input (' Zadej číslo: ' )
40+ if obsahuje_jen_cislice(odpoved):
41+ return int (odpoved) # máme výsledek, funkce končí
42+ else :
43+ print (' To nebylo číslo!' )
44+ # ... a zeptáme se znovu -- cyklus `while` pokračuje
45+ ```
4746
48- ## Vyvolání chyby
47+ Kde ale vzít funkci ` obsahuje_jen_cislice ` ?
48+ Nemá smysl ji psát znovu – funkce ` int ` sama nejlíp pozná, co se dá převést na
49+ číslo a co ne.
50+ A dokonce nám to dá vědět – chybou, kterou můžeš * zachytit* .
51+
52+ > [ note]
53+ > Ono „obsahuje_jen_cislice“ v Pythonu existuje. Dokonce několikrát.
54+ > Místo řešení problému to ale spíš ilustruje, v čem problém spočívá:
55+ > * Řetězcová metoda ` isnumeric ` vrací ` True ` pokud řetězec obsahuje číslice:
56+ > ` '123'.isnumeric() ` je pravda; ` 'abc'.isnumeric() ` nepravda.
57+ > Problém je, že funkci ` int ` potřebuje jeden konkrétní druh číslic:
58+ > pro řetězce jako ` '½' ` nebo ` '௩三๓໓ ` ' (trojka v tamilském, japonském,
59+ > thajském nebo laoském písmu) platí ` isnumeric ` , ale ` int ` si na nich
60+ > vyláme zuby stejně jako na ` 'abc' ` .
61+ > * Řetězcová metoda ` isdecimal ` vrací ` True ` pokud řetězec obsahuje arabské
62+ > číslice 0-9. To už je lepší, ale stejně to úplně nesedí: ` int ` si poradí
63+ > s mezerou na začátku, např. s ` ' 3' ` , ale funkce ` isdecimal ` takový řetězec
64+ > odmítne.
65+ >
66+ > Chceš-li zjistit jestli funkce ` int ` umí daný řetězec převést na číslo,
67+ > nejlepší je použít přímo funkci ` int ` .
4968
50- Chybu neboli * výjimku* (angl. * exception* ) můžeš vyvolat i {{gnd('sám', 'sama')}},
51- pomocí příkazu ` raise ` .
52- Za příkaz dáš jméno výjimky a pak do závorek nějaký popis toho, co je špatně.
5369
54- ``` python
55- VELIKOST_POLE = 20
70+ ## Ošetření chyby
5671
57- def over_cislo (cislo ):
58- if 0 <= cislo < VELIKOST_POLE :
59- print (' OK!' )
60- else :
61- raise ValueError (' Čislo {n} není v poli!' .format(n = cislo))
72+ Pro zachycení chyby má Python příkaz ` try ` /` except ` .
73+
74+ ``` python
75+ def nacti_cislo ():
76+ while True :
77+ odpoved = input (' Zadej číslo: ' )
78+ try :
79+ return int (odpoved)
80+ except ValueError :
81+ print (' To nebylo číslo!' )
6282```
6383
64- Všechny typy výjimek, které jsou zabudované
65- v Pythonu, jsou popsané [ v dokumentaci] ( https://docs.python.org/3.2/library/exceptions.html#exception-hierarchy ) .
84+ Jak to funguje?
85+ Příkazy v bloku uvozeném příkazem ` try ` se normálně provádějí, ale když
86+ nastane uvedená výjimka, Python přeskočí zbytek bloku ` try ` a provede všechno
87+ v bloku ` except ` .
88+ Pokud výjimka nenastala, přeskočí se celý blok ` except ` .
89+
90+
91+ ## Druhy chyb
6692
67- Pro nás jsou (nebo budou) důležité tyto:
93+ A co je to ` ValueError ` ? To je typ chyby.
94+ Podobných typů je spousta.
95+ Všechny jsou popsané [ v dokumentaci] ( https://docs.python.org/3/library/exceptions.html#exception-hierarchy ) ; pro nás jsou (nebo budou) důležité tyto:
6896
6997``` plain
7098BaseException
@@ -74,86 +102,57 @@ BaseException
74102 ├── ArithmeticError
75103 │ ╰── ZeroDivisionError dělení nulou
76104 ├── AssertionError nepovedený příkaz `assert`
77- ├── AttributeError neexistující atribut, např. 'abc'.len
105+ ├── AttributeError neexistující atribut/metoda , např. 'abc'.len
78106 ├── ImportError nepovedený import
79107 ├── LookupError
80108 │ ╰── IndexError neexistující index, např. 'abc'[999]
81109 ├── NameError použití neexistujícího jména proměnné
82110 │ ╰── UnboundLocalError použití proměnné, která ještě nebyla nastavená
83- ├── SyntaxError špatná syntaxe – program je nečitelný/nepoužitelný
111+ ├── SyntaxError špatná syntaxe, program je nečitelný/nepoužitelný
84112 │ ╰── IndentationError špatné odsazení
85- │ ╰── TabError kombinování mezer a tabulátorů
113+ │ ╰── TabError kombinování mezer a tabulátorů v odsazení
86114 ├── TypeError špatný typ, např. len(9)
87115 ╰── ValueError špatná hodnota, např. int('xyz')
88116```
89117
90-
91- ## Ošetření chyby
92-
93- A proč jich je tolik druhů?
94- Abys je mohl{{a}} chytat!
95- Následující funkce je připravená na to, že
96- funkce ` int ` může selhat, pokud uživatel nezadá číslo:
97-
98- ``` python
99- def nacti_cislo ():
100- odpoved = input (' Zadej číslo: ' )
101- try :
102- cislo = int (odpoved)
103- except ValueError :
104- print (' To nebylo číslo! Pokračuji s nulou.' )
105- cislo = 0
106- return cislo
107- ```
108-
109- Jak to funguje?
110- Příkazy v bloku uvozeném příkazem ` try ` se normálně provádějí, ale když
111- nastane uvedená výjimka, Python místo ukončení programu provede
112- všechno v bloku ` except ` .
113- Když výjimka nenastane, blok ` except ` se přeskočí.
118+ Tohle si není potřeba pamatovat – druh chyby, kterou je potřeba zachytit,
119+ vždy najdeš v příslušné chybové hlášce.
114120
115121Když odchytáváš obecnou výjimku,
116122chytnou se i všechny podřízené typy výjimek –
117123například ` except ArithmeticError: ` zachytí i ` ZeroDivisionError ` .
118- A ` except Exception: ` zachytí všechny
119- výjimky, které běžně chceš zachytit.
124+ A ` except Exception: ` zachytí * všechny* výjimky, které běžně chceš zachytit.
120125
121126
122127## Nechytej je všechny!
123128
124- Většinu chyb ale není potřeba ošetřovat.
129+ Většinu chyb * není* potřeba ošetřovat.
125130
126- Nastane-li nečekaná situace, je téměř vždy
127- * mnohem* lepší program ukončit, než se snažit
128- pokračovat dál počítat se špatnými hodnotami.
131+ Nastane-li * nečekaná* situace, je téměř vždy
132+ mnohem lepší program ukončit, než se snažit
133+ pokračovat dál a počítat se špatnými hodnotami.
129134Navíc chybový výstup, který Python standardně
130135připraví, může hodně ulehčit hledání chyby.
131136
132- „Ošetřování” chyb jako ` KeyboardInterrupt `
133- je ještě horší: může způsobit, že program nepůjde
134- ukončit, když bude potřeba.
137+ Zachytávej tedy jenom ty chyby, které * očekáváš* – víš přesně, která chyba může
138+ nastat a proč; máš možnost správně zareagovat.
135139
136- Příkaz ` try/except ` proto používej
137- jen v situacích, kdy výjimku očekáváš – víš přesně, která chyba může
138- nastat a proč, a máš možnost ji opravit.
139- Pro nás to typicky bude načítání vstupu od uživatele.
140- Po špatném pokusu o zadání je dobré se ptát znovu, dokud uživatel nezadá
141- něco smysluplného:
140+ V našem příkladu to platí pro ` ValueError ` z funkce ` int ` : víš že uživatel
141+ nemusí vždy zadat číslo ve správném formátu a víš že správná
142+ reakce na tuhle situaci je problém vysvětlit a zeptat se znovu.
142143
143- ``` python
144- def nacti_cislo ():
145- while True :
146- odpoved = input (' Zadej číslo: ' )
147- try :
148- return int (odpoved)
149- except ValueError :
150- print (' To nebylo číslo! Zkus to znovu.' )
151- ```
144+ Co ale dělat, kdyš uživatel chce ukončit program a zmáčkne
145+ <kbd >Ctrl</kbd >+<kbd >C</kbd >?
146+ Nebo když se mu porouchá klávesnice a selže funkce ` input ` ?
147+ Nejlepší reakce na takovou nečekanou situaci ukončit program a informovat
148+ uživatele (nebo lépe, programátora), že (a kde) je něco špatně.
149+ Neboli vypsat chybovou hlášku.
150+ A to se stane normálně, bez ` try ` .
152151
153152
154153## Další přílohy k ` try `
155154
156- Kromě ` except ` existují dva jiné bloky,
155+ Pro úplnost: kromě ` except ` existují dva jiné bloky,
157156které můžeš „přilepit“ k ` try ` , a to ` else ` a ` finally ` .
158157První se provede, když v ` try ` bloku
159158žádná chyba nenastane; druhý se provede vždy – ať
@@ -182,54 +181,49 @@ finally:
182181```
183182
184183
185- ## Úkol
186-
187- Doplň do geometrické kalkulačky (nebo 1-D piškvorek, máš-li je) ošetření chyby,
188- která nastane když uživatel nezadá číslo.
189184
190- {% filter solution %}
185+ ## Vyvolání chyby
191186
192- Možné řešení pro geometrickou kalkulačku:
187+ Občas se stane, že výjimku budeš potřebovat vyvolat {{gnd('sám', 'sama')}}.
193188
194- ``` python
189+ Často se to stává když píšeš nějakou obecnou funkci.
190+ Třeba funkci na výpočet obsahu čtverce.
191+ Co se stane, když někdo zavolá ` obsah_ctverce(-5) ` ?
195192
196- while True :
197- try :
198- strana = float (input (' Zadej stranu čtverce v centimetrech: ' ))
199- except ValueError :
200- print (' To nebylo číslo!' )
201- else :
202- if strana <= 0 :
203- print (' To nedává smysl!' )
204- else :
205- break
193+ * Zadal-li ono ` -5 ` uživatel, je potřeba mu vynadat a zeptat se znovu.
194+ * Naměřil-li ` -5 ` nějaký robotický aparát, je potřeba ho líp zkalibrovat.
195+ * Vyšel-li čtverec se stranou ` -5 ` v nějakém výpočtu, je nejspíš potřeba opravit
196+ chybu v tom výpočtu.
206197
207- print (' Obvod čtverce se stranou' , strana, ' je' , 4 * strana, ' cm' )
208- print (' Obsah čtverce se stranou' , strana, ' je' , strana * strana, ' cm2' )
198+ Samotná funkce ` obsah_ctverce ` ale „neví“, proč ji někdo volá.
199+ Jejím úkolem je jen něco spočítat.
200+ Měla by být použitelná ve všech případech výše – a v mnoha dalších.
209201
210- ```
202+ Když někdo zavolá ` obsah_ctverce(-5) ` , * neexistuje* správný výsledek, který by
203+ funkce mohla vrátit.
204+ Místo vrácení výsledku musí tato funkce * signalizovat chybu* .
205+ S tou se pak může program, který ` obsah_ctverce(-5) ` zavolal,
206+ vypořádat – vynadat uživateli, zkalibrovat měřák, nebo, pokud na chybu není
207+ připravený, sám skončit s chybou (a upozornit tak programátora, že je něco
208+ špatně).
211209
212- Možné řešení pro 1-D piškvorky:
210+ Jak na to prakticky?
211+ Chybu můžeš vyvolat pomocí příkazu ` raise ` .
212+ Za příkaz dáš druh výjimky a pak do závorek nějaký popis toho, co je špatně.
213213
214214``` python
215- def tah_hrace (pole ):
216- while True :
217- try :
218- pozice = int (input (' Kam chceš hrát? (0..19) ' ))
219- except ValueError :
220- print (' To není číslo!' )
221- else :
222- if pozice < 0 or pozice >= len (pole):
223- print (' Nemůžeš hrát venku z pole!' )
224- elif pole[pozice] != ' -' :
225- print (' Tam není volno!' )
226- else :
227- break
228-
229- pole = pole[:pozice] + ' o' + pole[pozice + 1 :]
230- return pole
215+ def obsah_ctverce (strana ):
216+ if strana > 0 :
217+ return strana ** 2
218+ else :
219+ raise ValueError (f ' Strana musí být kladná, číslo { strana} kladné není! ' )
220+ ```
231221
222+ Podobně jako ` return ` , i příkaz ` raise ` ukončí funkci.
223+ A nejen tu – pokud na tuhle konkrétní chybu není program předem připravený,
224+ ukončí se celý program.
232225
233- print (tah_hrace(' -x----' ))
234- ```
235- {% endfilter %}
226+ Ze začátku není u ` raise ` příliš důležité dumat nad tím, který typ výjimky je
227+ ten správný.
228+ Klidně „střílej od boku“.
229+ ` ValueError ` bývá často správná volba.
0 commit comments