Lekce 19 - Ošetření výjimek v Pythonu
V předchozí lekci, Dekorátory podruhé - Parametrické a třídní dekorátory, jsme dokončili téma s dekorátory.
V tomto Python tutoriálu si ukážeme, jak ošetřit výjimky v programu a
jak reagovat na uživatelské či jiné chyby. Naše programy zatím vždy
"spadly" a dále již nepokračovaly. To samozřejmě není, jak si uživatel
představuje, že budou fungovat
Prozraďme si malé tajemství - Čím hloupějšího uživatele
budeme předpokládat a upravíme pro něj program, tím lépe se program bude
používat, protože bude "blbuvzdorný" a jednoduchý!
Ošetření chyb
Ve většině námi dosud vytvořených programů jsme uživateli umožnili spáchat chybu při číselném vstupu. Pokud by tedy uživatel zadal namísto čísla např. písmeno, náš program by spadl.
Nyní si tedy ukážeme, jak takovéto chyby ošetřit. Ošetření se
provádí pomocí bloku try–except:
try: # Blok příkazů, co může vyvolat chybu except: # Blok příkazů, co se spustí, když chyba nastane
Pokud je kód, který může vyvolat chybu, v bloku try,
namísto pádu programu se v případě chyby blok try přeruší a
program pokračuje do bloku except.
Příklad
Úplně jednoduché použití ošetření chyb si ukažme na programu, co načte dvě čísla a vydělí první tím druhým:
try: delenec = float(input("Zadejte číslo, které chcete dělit: ")) delitel = float(input("Zadejte číslo, kterým chcete dělit: ")) vysledek = delenec / delitel print(f"Výsledek dělení je: {vysledek}") except: print("Došlo k chybě!")
Pokud nezadáme správně první číslo a zadáme místo něj např. text, nebo nezadáme správně druhé číslo, nebo budeme dělit nulou, program neupadne, ale vypíše hlášku "Došlo k chybě!" a poběží dále:
Konzolová aplikace
Zadejte číslo, které chcete dělit: nezadám
Došlo k chybě!
Druhy chyb
Chybám se v Pythonu (a v objektových jazycích obecně) říká výjimky. Ty základní jsou následující:
SyntaxError– chyba je ve zdrojovém kódu,ZeroDivisionError– pokus o dělení nulou,TypeError– nesprávné použití datových typů, např. sčítání řetězce a čísla,ValueError– nesprávná hodnota.
Všechny výjimky najdeme v dokumentaci Pythonu.
V Pythonu můžeme zachytit i jen konkrétní chyby a i jejich chybovou zprávu. Pak musíme kód upravit takto:
except jmeno_vyjimky as chyba: #Text výjimky se uloží do proměnné chyba.
Bloky else a
finally
Do bloku try-except lze případně přidat i
další dva bloky:
- Blok
else, který se hodí pro kód, který má běžet jen když vše vtryproběhne v pořádku. - Blok
finally, který se potom spustí vždy, ať k chybě došlo či nikoli. Typicky se používá na úklid – zavření souborů, uvolnění zdrojů, odhlášení atd.
Pojďme si to celé zrekapitulovat:
try: # Kód, který může vyvolat chybu except: # Spustí se, když chyba nastane else: # Spustí se, jen když v try NEBYLA výjimka finally: # Spustí se vždy.
Pokročilý příklad
Ukažme si příklad, který využije všechna klíčová slova bloku
try–except a zároveň bude vypisovat
inteligentněji co se pokazilo podle typu odchycené výjimky:
pokracovat = True while pokracovat: try: delenec = float(input("Zadejte číslo, které chcete dělit: ")) delitel = float(input("Zadejte číslo, kterým chcete dělit: ")) vysledek = delenec / delitel except ZeroDivisionError: print("Dělení nulou není možné!") except ValueError: print("Byla zadána neplatná hodnota!") else: print(f"Výsledek dělení je: {vysledek}") finally: opustit = input("Chcete ukončit program? (ano/ne): ").lower() if opustit == "ano": pokracovat = False
Kód si vysvětlíme. V tomto kódu se program uživatele zeptá, která
čísla chce dělit. Pokud uživatel zkusí dělit nulou, program chybu zachytí
a vypíše chybovou zprávu. Stejně tak dojde k zachycení chyby v případě,
že uživatel vloží něco jiného než číslo. Blok else jsme
použili pro výpis výsledku dělení v případě, že nedojde k výjimce.
Blok finally pak umožňuje uživateli opustit cyklus a ukončit
program.
Kalkulačka
Nyní si ukážeme, jak vytvořit jednoduchou objektovou aplikaci s odchytáváním výjimek. Vytvořme si kalkulačku. V případě, že uživatel nezadá číslo nebo při pokusu o dělení nulou zachytíme výjimku a vypíšeme chybu uživateli.
Logika kalkulačky
Vytvořme si soubor kalkulacka.py s třídou,
která bude obsahovat potřebné výpočty jako metody:
class Kalkulacka: def secti(self, a, b): return a + b def odecti(self, a, b): return a - b def vynasob(self, a, b): return a * b def vydel(self, a, b): return a / b
Hlavní skript
Komunikaci s uživatelem umístíme do hlavního skriptu
main.py, odkud budeme také ovládat objekt kalkulačky. Uživatele
se zeptáme na dvě čísla, se kterými bude chtít počítat. Celou logiku
zadávání vstupu od uživatele dáme do bloku try. Tedy když
nastane chyba typu ValueError, program skočí do bloku
except a vypíše chybu:
from kalkulacka import Kalkulacka kalkulacka = Kalkulacka() try: a = float(input("Zadej první číslo: ")) b = float(input("Zadej druhé číslo: ")) except ValueError: print("Chyba: zadaný vstup není číslo.")
Vždy je nejlepší do try bloku dávat pouze tu
část kódu, která může vyvolat chybu. Dále je doporučené chytat určitý
typ výjimky. Při porušení jednoho z těchto bodů zvyšujeme šanci, že
chytíme výjimku, se kterou jsme nepočítali a tak můžeme způsobit
neočekávané chování aplikace.
Zbytek programu provedeme ve větvi else, která se spustí,
když k chybě nedojde. Necháme si zadat operaci a podle ní poté zavoláme
danou metodu na objektu kalkulačky. Metoda kalkulacka.vydel()
může při dělení nulou vyvolat výjimku, její volání tedy obalíme do
try bloku a v případě chyby (except) chybu
vypíšeme:
from kalkulacka import Kalkulacka kalkulacka = Kalkulacka() try: a = float(input("Zadej první číslo: ")) b = float(input("Zadej druhé číslo: ")) except ValueError: print("Chyba: zadaný vstup není číslo.") else: operace = input("Vyber operaci (+, -, *, /): ") match operace: case "+": vysledek = kalkulacka.secti(a, b) case "-": vysledek = kalkulacka.odecti(a, b) case "*": vysledek = kalkulacka.vynasob(a, b) case "/": try: vysledek = kalkulacka.vydel(a, b) except ZeroDivisionError as e: vysledek = "Chyba: nelze dělit nulou." case _: vysledek = "Chyba: Neplatná operace." print("Výsledek:", vysledek)
Zkusme si program spustit a zadat neplatný vstup:
Konzolová aplikace
Zadej první číslo: jedna
Chyba: zadaný vstup není číslo.
A zkusme si dělit nulou:
Konzolová aplikace
Zadej první číslo: 10
Zadej druhé číslo: 0
Vyber operaci (+, -, *, /): /
Výsledek: Chyba: nelze dělit nulou.
raise
Doposud jsme pouze zachytávali chyby, které vyvolal sám Python (např.
dělení nulou). Občas se nám ale hodí výjimku vyvolat úmyslně,
například když uživatel zadá hodnotu, která je sice technicky platná, ale
pro náš program nedává smysl. K tomu slouží příkaz
raise.
Ukážeme si to na metodě kalkulačky, která bude počítat druhou
odmocninu. V Pythonu lze odmocnit i záporné číslo, ale výsledek je pak
komplexní číslo, které jsme se rozhodli v naší kalkulačce nepodporovat.
Proto se rozhodneme takový vstup zakázat a vyvoláme vlastní výjimku.
Doplňme soubor kalkulacka.py o následující metodu:
def odmocni(self, a): if a < 0: raise ValueError("Druhá odmocnina ze záporného čísla není podporována") return a ** (1 / 2)
Druhou odmocninu technicky vypočítáme umocněním čísla na
jednu polovinu. Stejně tak bychom mohli použít i matematickou funkci
sqrt().
Teď si můžeme v hlavním programu vyzkoušet, jak se raise
chová. Pokud si nechcete přepisovat původní main.py, vytvořte
si například main_odmocnina.py a budeme spouštět ten:
from kalkulacka import Kalkulacka kalkulacka = Kalkulacka() try: cislo = float(input("Zadej číslo pro odmocninu: ")) vysledek = kalkulacka.odmocni(cislo) except ValueError as e: vysledek = "Chyba: nezadáno číslo nebo zadáno záporné číslo." print("Výsledek:", vysledek)
Pokud zadáme kladné číslo, program bez problému vypíše odmocninu:
Konzolová aplikace
Zadej číslo pro odmocninu: 100
Výsledek: 10.0
Pokud zadáme číslo záporné, metoda odmocni() pomocí
raise vyvolá výjimku ValueError a program ji
zachytí v except a vypíše srozumitelnou chybovou hlášku:
Konzolová aplikace
Zadej číslo pro odmocninu: -1
Výsledek: Chyba: nezadáno číslo nebo zadáno záporné číslo.
V příští lekci, Vlastnosti v Pythonu, se budeme zabývat vlastnostmi neboli gettery a settery, které umožní snazší nastavování a validaci hodnot atributů.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 16x (6.94 kB)
Aplikace je včetně zdrojových kódů v jazyce Python
