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+ Vezměme 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+ nastene 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 neco, 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+ Kdybychom měli 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+ Nechceme 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ůžeme * zachytit* .
4951
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ě.
5352
54- ``` python
55- VELIKOST_POLE = 20
53+ ## Ošetření chyby
5654
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))
55+ Pro zachycení chyby má Python příkaz ` try ` /` except ` .
56+
57+ ``` python
58+ def nacti_cislo ():
59+ while True :
60+ odpoved = input (' Zadej číslo: ' )
61+ try :
62+ return int (odpoved)
63+ except ValueError :
64+ print (' To nebylo číslo!' )
6265```
6366
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 ) .
67+ Jak to funguje?
68+ Příkazy v bloku uvozeném příkazem ` try ` se normálně provádějí, ale když
69+ nastane uvedená výjimka, Python přeskočí zbytek bloky ` try ` a provede všechno
70+ v bloku ` except ` .
71+ Pokud výjimka nenastala, přeskočí se celý blok ` except ` .
72+
73+
74+ ## Druhy chyb
6675
67- Pro nás jsou (nebo budou) důležité tyto:
76+ A co je to ` ValueError ` ? To je typ chyby.
77+ Podobných typů je spousta.
78+ 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:
6879
6980``` plain
7081BaseException
@@ -74,86 +85,51 @@ BaseException
7485 ├── ArithmeticError
7586 │ ╰── ZeroDivisionError dělení nulou
7687 ├── AssertionError nepovedený příkaz `assert`
77- ├── AttributeError neexistující atribut, např. 'abc'.len
88+ ├── AttributeError neexistující atribut/metoda , např. 'abc'.len
7889 ├── ImportError nepovedený import
7990 ├── LookupError
8091 │ ╰── IndexError neexistující index, např. 'abc'[999]
8192 ├── NameError použití neexistujícího jména proměnné
8293 │ ╰── UnboundLocalError použití proměnné, která ještě nebyla nastavená
83- ├── SyntaxError špatná syntaxe – program je nečitelný/nepoužitelný
94+ ├── SyntaxError špatná syntaxe, program je nečitelný/nepoužitelný
8495 │ ╰── IndentationError špatné odsazení
85- │ ╰── TabError kombinování mezer a tabulátorů
96+ │ ╰── TabError kombinování mezer a tabulátorů v odsazení
8697 ├── TypeError špatný typ, např. len(9)
8798 ╰── ValueError špatná hodnota, např. int('xyz')
8899```
89100
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čí.
114-
115101Když odchytáváš obecnou výjimku,
116102chytnou se i všechny podřízené typy výjimek –
117103například ` except ArithmeticError: ` zachytí i ` ZeroDivisionError ` .
118- A ` except Exception: ` zachytí všechny
119- výjimky, které běžně chceš zachytit.
104+ A ` except Exception: ` zachytí * všechny* výjimky, které běžně chceš zachytit.
120105
121106
122107## Nechytej je všechny!
123108
124- Většinu chyb ale není potřeba ošetřovat.
109+ Většinu chyb * není* potřeba ošetřovat.
125110
126- Nastane-li nečekaná situace, je téměř vždy
127- * mnohem* lepší program ukončit, než se snažit
111+ Nastane-li * nečekaná* situace, je téměř vždy
112+ mnohem lepší program ukončit, než se snažit
128113pokračovat dál počítat se špatnými hodnotami.
129114Navíc chybový výstup, který Python standardně
130115připraví, může hodně ulehčit hledání chyby.
131116
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.
117+ Zachytávej tedy jenom ty chyby, které * očekáváš* – víš přesně, která chyba může
118+ nastat a proč, a máš možnost správně zareagovat.
135119
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:
120+ V našem příkladu to platí pro ` ValueError ` z funkce ` int ` .
142121
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- ```
122+ Co ale dělat, kdyš uživatel chce ukončit program a zmáčkne
123+ <kbd >Ctrl</kbd >+<kbd >C</kbd >?
124+ Nebo když se mu porouchá klávesnice a selže funkce ` input ` ?
125+ V obou případech je nejlepší reakce ukončit program a informovat
126+ programátora, že (a kde) je něco špatně.
127+ Neboli vypat chybovou hlášku – to, co se stane normálně, bez ` try ` .
152128
153129
154130## Další přílohy k ` try `
155131
156- Kromě ` except ` existují dva jiné bloky,
132+ Pro úplnost: kromě ` except ` existují dva jiné bloky,
157133které můžeš „přilepit“ k ` try ` , a to ` else ` a ` finally ` .
158134První se provede, když v ` try ` bloku
159135žádná chyba nenastane; druhý se provede vždy – ať
@@ -182,54 +158,49 @@ finally:
182158```
183159
184160
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.
189161
190- {% filter solution %}
162+ ## Vyvolání chyby
191163
192- Možné řešení pro geometrickou kalkulačku:
164+ Občas se stane, že výjimku budeš potřebovat vyvolat {{gnd('sám', 'sama')}}.
193165
194- ``` python
166+ Často se to stává když píšeš nějakou obecnou funkci.
167+ Třeba funkci na výpočet obsahu čtverce.
168+ Co se stane, když někdo zavolá ` obsah_ctverce(-5) ` ?
195169
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
170+ * Zadal-li ono ` -5 ` uživatel, je potřeba mu vynadat a zeptat se znovu.
171+ * Naměřil-li ` -5 ` nějaký robotický aparát, je potřeba ho líp zkalibrovat.
172+ * Vyšel-li čtverec se stranou ` -5 ` v nějakém výpočtu, je nejspíš potřeba opravit
173+ chybu v tom výpočtu.
206174
207- print (' Obvod čtverce se stranou' , strana, ' je' , 4 * strana, ' cm' )
208- print (' Obsah čtverce se stranou' , strana, ' je' , strana * strana, ' cm2' )
175+ Samotná funkce ` obsah_ctverce ` ale „neví“, proč ji někdo volá.
176+ Jejím úkolem je jen něco spočítat.
177+ Měla by být použitelná ve všech případech výše – a v mnoha dalších.
209178
210- ```
179+ Když někdo zavolá ` obsah_ctverce(-5) ` , * neexistuje* správný výsledek, který by
180+ funkce mohla vrátit.
181+ Místo vracení výsledku musí tato funkce * signalizovat chybu* .
182+ S tou se pak může program, který ` obsah_ctverce(-5) ` zavolal,
183+ vypořádat – vynadat uživateli, zkalibrovat měřák, nebo, pokud na chybu není
184+ připravený, sám skončit s chybou (a upozornit tak programátora, že je něco
185+ špatně).
211186
212- Možné řešení pro 1-D piškvorky:
187+ Jak na to prakticky?
188+ Chybu můžeš vyvolat pomocí příkazu ` raise ` .
189+ Za příkaz dáš druh výjimky a pak do závorek nějaký popis toho, co je špatně.
213190
214191``` 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
192+ def obsah_ctverce (strana ):
193+ if strana > 0 :
194+ return strana * strana
195+ else :
196+ raise ValueError (f ' Strana musí být kladná, číslo { strana} kladné není! ' )
197+ ```
231198
199+ Podobně jako ` return ` , i příkaz ` raise ` ukončí funkci.
200+ A nejen tu – pokud na tuhle konkrétní chybu program předem připravený,
201+ ukončí se celý program.
232202
233- print (tah_hrace(' -x----' ))
234- ```
235- {% endfilter %}
203+ Ze začátku není příliš důležité dumat nad tím, který typ výjimky je ten
204+ správný.
205+ Klidně „střílej od boku“.
206+ ` ValueError ` bývá často správná volba.
0 commit comments