Keď počas behu programu nastane chyba – delenie nulou, neplatný vstup, chýbajúci súbor –, Python vyvolá výnimku. Ak ju nikto nezachytí, program skončí s chybovým hlásením. V tejto téme sa naučíš výnimky zachytávať a rozumne na ne reagovať: požiadať o nový vstup, použiť náhradnú hodnotu alebo vypísať zrozumiteľnú správu. Naučíš sa aj vyvolať vlastnú výnimku, keď funkcia dostane nezmyselné údaje.
Čo sa naučíš
- zachytiť výnimku blokom
try – excepta pochopiť, ako sa program pri chybe vykonáva, - rozlišovať typy výnimiek a zachytávať iba tie, ktoré očakávaš,
- používať vetvy
elseafinally, - vyvolať vlastnú výnimku príkazom
raise, - napísať kontrolu vstupu, ktorá sa pýta, kým nedostane správnu hodnotu.
1Čo je výnimka
Výstup (program skončí chybou):
Vek: dva Traceback (most recent call last): File "program.py", line 1, in <module> vek = int(input("Vek: ")) ^^^^^^^^^^^^^^^^^^^ ValueError: invalid literal for int() with base 10: 'dva'
int("dva") nevie urobiť z textu číslo, a tak vyvolá výnimku ValueError. Nik ju nezachytil, takže Python program ukončil a vypísal hlásenie (traceback). Výnimka nesie typ (ValueError) a správu (invalid literal for int() with base 10: 'dva').
2try a except
Kód, v ktorom môže nastať chyba, dáme do bloku try. Do bloku except napíšeme, čo sa má stať, keď chyba nastane:
Výstup:
Vek: dva To nie je celé číslo. Program pokračuje.
Ako sa vykonáva:
- Vykonávajú sa príkazy v bloku
try. - Ak nenastane chyba, blok
exceptsa preskočí. - Ak nastane chyba, zvyšok bloku
trysa preskočí a vykoná saexcept– ak zodpovedá typ výnimky. - Potom program normálne pokračuje za celou konštrukciou.
Pre vstup 17 by sa vypísalo „O rok budeš mať 18“ a „Program pokračuje.“
2.1Konkrétny typ výnimky
Za except píšeme typ výnimky, ktorú chceme zachytiť. Iné výnimky zachytené nebudú – a to je dobre: nechceme potichu „prehltnúť“ chyby, ktoré sme nečakali (napríklad preklep v mene premennej).
Viac typov môžeme ošetriť viacerými vetvami except:
Výstup:
Delenec: 10 Deliteľ: 0 Nulou deliť nemožno.
Rovnaké ošetrenie pre viac typov: except (ValueError, ZeroDivisionError):.
2.2Správa výnimky: as
Zápis except Typ as e uloží výnimku do premennej e; str(e) alebo print(e) vypíše jej správu:
Výstup:
Chyba: list index out of range3else a finally
Konštrukcia môže mať ešte dve vetvy:
else– vykoná sa, ak nenastala žiadna výnimka,finally– vykoná sa vždy, s chybou aj bez nej (napríklad na upratanie, zatvorenie súboru, záverečnú správu).
Výstup:
vydel(10, 4):
výsledok: 2.5
hotovo
vydel(1, 0):
delenie nulou
hotovoDo try dávaj iba riadky, v ktorých môže nastať očakávaná chyba. Pokračovanie, ktoré má prebehnúť iba pri úspechu, patrí do else.
4Typy výnimiek
| Výnimka | Kedy nastane | Príklad |
|---|---|---|
ValueError | hodnota má správny typ, ale nezmyselný obsah | int("abc"), int("3.5") |
TypeError | operácia s nevhodným typom | "a" + 1, len(5) |
ZeroDivisionError | delenie nulou | 5 / 0, 5 % 0 |
IndexError | index mimo zoznamu alebo reťazca | [1, 2][5] |
KeyError | kľúč v slovníku neexistuje | {"a": 1}["b"] |
NameError | neznáme meno (preklep, nepriradená premenná) | print(x) |
AttributeError | hodnota nemá takú metódu | (5).upper() |
FileNotFoundError | súbor neexistuje | open("nie.txt") |
RecursionError | príliš hlboká rekurzia | funkcia bez základného prípadu |
>>> int("3.5") ValueError: invalid literal for int() with base 10: '3.5' >>> len(5) TypeError: object of type 'int' has no len() >>> {"a": 1}["b"] KeyError: 'b' >>> "text".upper(1) TypeError: str.upper() takes no arguments (1 given)
Všetky bežné výnimky sú „druhom“ výnimky Exception. Zápis except Exception: preto zachytí takmer všetko – používaj ho iba výnimočne a nikdy nepíš samotné except: bez typu. Zachytil by aj chyby, ktoré chceš vidieť a opraviť.
5Vyvolanie výnimky: raise
Výnimku môžeme vyvolať aj sami príkazom raise. Robí sa to vo funkcii, ktorá dostane nezmyselné údaje a nevie s nimi rozumne pokračovať – namiesto chybného výsledku radšej jasne oznámi problém:
Výstup:
4.0
Chyba: odmocnina zo záporného číslaKto funkciu volá, sa môže rozhodnúť, či výnimku zachytí. Ak ju nezachytí, program skončí so správou, ktorú sme napísali:
Výstup (program skončí chybou):
Traceback (most recent call last):
File "program.py", line 6, in <module>
nastav_vek(200)
File "program.py", line 3, in nastav_vek
raise ValueError(f"neplatný vek: {vek}")
ValueError: neplatný vek: 2006Kontrola vstupu
Typické použitie výnimiek: pýtať sa na vstup dovtedy, kým nie je správny. Cyklus while True skončí break až po úspešnom prevode:
Výstup:
Zadaj celé číslo: sedem Neplatný vstup, skús to znova. Zadaj celé číslo: 7.5 Neplatný vstup, skús to znova. Zadaj celé číslo: 7 Načítané číslo: 7
Často treba skontrolovať aj rozsah. Pohodlné je zabaliť kontrolu do funkcie, ktorú použiješ v rôznych programoch:
Výstup:
Známka (1 – 5): 0 Číslo musí byť od 1 do 5. Známka (1 – 5): abc Zadaj celé číslo. Známka (1 – 5): 11 Číslo musí byť od 1 do 5. Známka (1 – 5): 4 Zapísaná známka: 4
Rozsah kontrolujeme obyčajnou podmienkou – výnimky použijeme iba tam, kde chybu nevieme ľahko predvídať (prevod textu na číslo, otvorenie súboru).
7Riešené úlohy
7.1Bezpečný priemer
Zadanie: Napíš funkciu priemer(cisla), ktorá vráti priemer zoznamu. Pre prázdny zoznam nech vyvolá ValueError so zrozumiteľnou správou. Vyskúšaj ju na správnom aj prázdnom zozname.
Výstup:
[4, 8, 6] → 6.0
[] → chyba: priemer prázdneho zoznamu neexistuje7.2Súbor s chybnými riadkami
Zadanie: V súbore je na každom riadku jedno číslo, niektoré riadky sú však chybné. Spočítaj súčet platných čísel a vypíš, ktoré riadky boli chybné.
Súbor merania.txt:
12 7.5 chyba -3 1e2
Riešenie: Každý riadok skúsime previesť na číslo. Chybný riadok nezastaví celý program – iba si ho poznačíme a pokračujeme ďalším. Zachytávame aj FileNotFoundError, ak by súbor chýbal.
Výstup:
Súčet: 116.5
Chybné riadky: [3, 5]Prázdny riadok (riadok 5) je tiež chybný – float("\n") nie je číslo. 1e2 je platný zápis čísla 100.
7.3Hádaj číslo s kontrolou vstupu
Zadanie: Počítač si myslí číslo od 1 do 50. Program sa pýta na tipy; neplatný vstup (text, číslo mimo rozsahu) nezapočíta ako pokus.
Výstup:
Tip: 25 Viac. Tip: hm To nie je číslo. Tip: 40 Menej. Tip: 99 Iba čísla od 1 do 50. Tip: 33 Viac. Tip: 37 Uhádnuté! Počet pokusov: 4
8Časté chyby
- Samotné
except:(aleboexcept Exception:) zachytí aj chyby, ktoré zachytiť nechceš – napríklad preklep v mene premennej – a program sa tvári, že všetko je v poriadku. - Príliš veľký blok
try: keď je v ňom veľa riadkov, nevieš, ktorý chybu spôsobil. Dotrydaj iba rizikové riadky. - Výnimka namiesto podmienky: to, čo vieš jednoducho overiť (
if b != 0,if x in slovnik), over podmienkou. - Chýbajúci
breakvwhile Truecykle kontroly vstupu – cyklus sa nikdy neskončí. - Zabudnuté, že program po
exceptpokračuje – premenná, ktorá sa vtrynestihla priradiť, potom neexistuje.
Zhrnutie
- Výnimka = chyba počas behu; nezachytená výnimka ukončí program.
try:rizikový kód,except Typ:ošetrenie; pri chybe sa zvyšoktrypreskočí.- Zachytávaj konkrétne typy (
ValueError,ZeroDivisionError, …), nie všetko naraz. except Typ as e– správa výnimky;else– keď chyba nenastala;finally– vždy.raise ValueError("správa")vyvolá výnimku, keď funkcia dostane neplatné údaje.- Kontrola vstupu:
while True+try+breakpo úspešnom prevode; rozsah over podmienkou.
Úlohy na precvičenie
- Načítaj dve čísla a vypíš ich podiel; ošetri neplatný vstup aj delenie nulou.
- Napíš funkciu
nacitaj_float(vyzva), ktorá sa pýta, kým nedostane desatinné číslo (aj s desatinnou čiarkou). - Napíš funkciu
obsah_obdlznika(a, b), ktorá pri zápornej strane vyvoláValueError. - Zo slovníka cien vypíš cenu zadaného tovaru; ak tovar chýba, ošetri
KeyErrora vypíš správu. - Načítaj meno súboru; ak neexistuje, vypíš správu a požiadaj o meno znova.