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.
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 vtry
probě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.
Vylepšení kalkulačky
Nyní se pokusíme vylepšit jednoduchou kalkulačku o ošetření chyb, kterou jsme si vytvořili v základech programování. Její originální kód je následující:
print("Vítejte v kalkulačce") pokracovat = "ano" while pokracovat == "ano": a = float(input("Zadejte první číslo: ")) b = float(input("Zadejte druhé číslo: ")) print("Zvolte si operaci:") print("1 - sčítání") print("2 - odčítání") print("3 - násobení") print("4 - dělení") volba = int(input()) vysledek = 0.0 match volba: case 1: vysledek = a + b case 2: vysledek = a - b case 3: vysledek = a * b case 4: if b != 0: vysledek = a / b else: print("Nulou nelze dělit!") vysledek = "N/A" if 0 < volba < 5: print(f"Výsledek: {vysledek}") else: print("Neplatná volba") pokracovat = input("Přejete si zadat další příklad? [ano/ne]: ") print("Děkuji za použití kalkulačky, aplikaci ukončíte libovolnou klávesou.")
Pusťme se do vylepšování kódu. Nejprve naprogramujeme "uživateli vzdornou" funkci na získání čísla ze vstupu:
def nacti_cislo(text_zadani, text_chyba): cislo_nezadano = True while cislo_nezadano: try: cislo = float(input(text_zadani)) cislo_nezadano = False except ValueError: print(text_chyba) return cislo
Program se tak dlouho opakuje v cyklu, dokud od uživatele nezíská
správný vstup. Řádek s float()
převede řetězec na desetinné
číslo.
Dále si naprogramujeme funkci, která umožní zadat pouze ano
a ne
:
def dalsi_priklad(): odpoved_nevalidni = True while odpoved_nevalidni: odpoved = input("\nPřejete si zadat další příklad? ano / ne: ").lower() if odpoved == "ano" or odpoved == "ne": odpoved_nevalidni = False else: print("Prosím, odpovězte 'ano' nebo 'ne'.") return odpoved == "ano" # Když bude v proměnné odpoved uložen řetězec "ano", funkce vrátí hodnotu True. Jinak vrátí False.
Dále musíme ošetřit, co se stane po volbě operace. Uživatel by mohl
zadat například číslo mimo interval <1;4>
a tím zvolit
neexistující operaci. Případně zadat čísla 5
a
0
a poté zvolit dělení. Náš program by pak skončil s
výjimkou ZeroDivisionError
. Musíme se tedy o tyto potenciální
chyby postarat. Je také nevhodné, aby funkce tiskla výsledek, lepší je
výsledek vrátit:
def proved_operaci(a, b): operace = 0 while operace not in [1, 2, 3, 4]: print("1 - sčítání") print("2 - odčítání") print("3 - násobení") print("4 - dělení") # Abychom nemuseli znovu při vybírání operace ošetřovat uživatelský vstup, využijeme zde naši již vytvořenou funkci # Její výstup (typu float) přetypujeme na int operace = int(nacti_cislo("Zadejte číslo pro vybranou operaci: ", "Neplatný vstup. Zadejte prosím číslo.")) if operace == 4 and b == 0: print("Nulou nelze dělit! Zkuste jinou operaci.") operace = 0 # Reset operace kvůli dělení nulou elif operace < 1 or operace > 4: print("Neplatná volba. Zadejte číslo odpovídající vybrané operaci.") # Ošetření neplatného vstupu match operace: case 1: return a + b case 2: return a - b case 3: return a * b case 4: return a / b
Hlavní cyklus programu se s našimi novými funkcemi značně zjednoduší:
print("Kalkulačka\n") pokracovat = True while pokracovat: prvni_cislo = nacti_cislo("Zadej číslo: ", "Neplatné číslo!\n") druhe_cislo = nacti_cislo("Zadej číslo: ", "Neplatné číslo!\n") vysledek_vypoctu = proved_operaci(prvni_cislo, druhe_cislo) print(f"Výsledek: {vysledek_vypoctu}") pokracovat = dalsi_priklad() print("Děkuji za použití kalkulačky, aplikaci ukončíte klávesou Enter.") input()
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 0x (1.87 kB)
Aplikace je včetně zdrojových kódů v jazyce Python