NOVINKA: Staň se datovým analytikem od 0 Kč a získej jistotu práce, lepší plat a nové kariérní možnosti. Více informací:

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 tryexcept:

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 v try 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 tryexcept 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

 

Předchozí článek
Dekorátory podruhé - Parametrické a třídní dekorátory
Všechny články v sekci
Objektově orientované programování v Pythonu
Přeskočit článek
(nedoporučujeme)
Vlastnosti v Pythonu
Článek pro vás napsal Filip Zeman
Avatar
Uživatelské hodnocení:
2 hlasů
Autor se věnuje vývojem aplikací hlavně kolem technologií .NET a to jak ve sféře desktopové, mobilní, tak hlavně samozřejmě webové. Nepohrdne ani Reactem či Djangem.
Aktivity