NOVINKA: Začni v IT jako webmaster s komplexním akreditovaným online kurzem Tvůrce WWW stránek. Zjisti více:
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:

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 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.

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

 

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í:
60 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