FINÁLNY VÝPREDAJ KREDITOV na ITnetwork je tu. Využi poslednú šancu a získaj až 80 % extra kreditov ZADARMO na náš interaktívny e-learning. Zisti viac:
Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.

19. diel - Ošetrenie výnimiek v Pythone Nové

V predchádzajúcej lekcii, Dekorátory druhýkrát - Parametrické a triedne dekorátory, sme dokončili tému s dekorátormi.

V tomto Python tutoriáli si ukážeme, ako ošetriť výnimky v programe a ako reagovať na používateľské či iné chyby. Naše programy doteraz vždy "spadli" a ďalej už nepokračovali. Takto si používateľ, samozrejme, nepredstavuje, že budú fungovať :) Prezraďme si malé tajomstvo – čím menej skúseného používateľa budeme pri návrhu programu predpokladať a čím lepšie mu program prispôsobíme, tým lepšie sa bude program používať, pretože bude "blbuvzdorný" a jednoduchý!

Ošetrenie chýb

Vo väčšine nami doteraz vytvorených programov sme používateľovi umožnili urobiť chybu pri číselnom vstupe. Ak by teda používateľ zadal namiesto čísla napríklad písmeno, náš program by spadol.

Teraz si teda ukážeme, ako takéto chyby ošetriť. Ošetrenie sa vykonáva pomocou bloku tryexcept:

try:
    # Block of statements that can raise an error
except:
    # Block of statements that runs when an error occurs

Ak je kód, ktorý môže vyvolať chybu, v bloku try, namiesto pádu programu sa v prípade chyby blok try preruší a program pokračuje do bloku except.

Príklad

Úplne jednoduché použitie ošetrenia chýb si ukážme na programe, ktorý načíta dve čísla a vydelí prvé druhým:

try:
    dividend = float(input("Enter the number you want to divide: "))
    divisor = float(input("Enter the number you want to divide by: "))
    result = dividend / divisor
    print(f"The division result is: {result}")
except:
    print("An error occurred!")

Ak nezadáme správne prvé číslo a zadáme namiesto neho napríklad text, nezadáme správne druhé číslo alebo budeme deliť nulou, program nespadne, ale vypíše hlášku "An error occurred!" a pobeží ďalej:

Konzolová aplikácia
Enter the number you want to divide: abc
An error occurred!

Druhy chýb

Chyby sa v Pythone (a v objektových jazykoch všeobecne) nazývajú výnimky. Tie základné sú nasledujúce:

  • SyntaxError – chyba je v zdrojovom kóde,
  • ZeroDivisionError – pokus o delenie nulou,
  • TypeError – nesprávne použitie dátových typov, napríklad sčítanie reťazca a čísla,
  • ValueError – nesprávna hodnota.

Všetky výnimky nájdeme v dokumentácii Pythonu.

V Pythone môžeme zachytiť iba konkrétne chyby a získať aj ich chybovú správu. Potom musíme kód upraviť takto:

except exception_name as error:
    #The exception text is stored in the error variable.

Bloky else a finally

Do bloku tryexcept možno prípadne pridať aj ďalšie dva bloky:

  • Blok else, ktorý sa hodí pre kód, ktorý má bežať len vtedy, keď všetko v try prebehne v poriadku.
  • Blok finally, ktorý sa potom spustí vždy, či už k chybe došlo, alebo nie. Typicky sa používa na upratovanie – zatvorenie súborov, uvoľnenie zdrojov, odhlásenie atď.

Poďme si to celé zrekapitulovať:

try:
    # Code that can raise an error
except:
    # Runs when an error occurs
else:
    # Runs only when there was NO exception in try
finally:
    # Always runs.

Pokročilý príklad

Ukážme si príklad, ktorý využije všetky kľúčové slová bloku tryexcept a zároveň bude inteligentnejšie vypisovať, čo sa pokazilo podľa typu zachytenej výnimky:

continue_program = True
while continue_program:
    try:
        dividend = float(input("Enter the number you want to divide: "))
        divisor = float(input("Enter the number you want to divide by: "))

        result = dividend / divisor

    except ZeroDivisionError:
        print("Division by zero is not possible!")

    except ValueError:
        print("An invalid value was entered!")

    else:
        print(f"The division result is: {result}")

    finally:
        exit_answer = input("Do you want to exit the program? (yes/no): ").lower()
        if exit_answer == "yes":
            continue_program = False

Kód si vysvetlíme. V tomto kóde sa program používateľa opýta, ktoré čísla chce deliť. Ak používateľ skúsi deliť nulou, program chybu zachytí a vypíše chybovú správu. Rovnako dôjde k zachyteniu chyby v prípade, že používateľ vloží niečo iné ako číslo. Blok else sme použili na výpis výsledku delenia v prípade, že nedôjde k výnimke. Blok finally potom umožňuje používateľovi opustiť cyklus a ukončiť program.

Kalkulačka

Teraz si ukážeme, ako vytvoriť jednoduchú objektovú aplikáciu so zachytávaním výnimiek. Vytvorme si kalkulačku. V prípade, že používateľ nezadá číslo alebo sa pokúsi deliť nulou, zachytíme výnimku a vypíšeme používateľovi chybu.

Logika kalkulačky

Vytvorme si súbor calculator.py s triedou Calculator, ktorá bude obsahovať potrebné výpočty ako metódy:

class Calculator:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        return a / b

Hlavný skript

Komunikáciu s používateľom umiestnime do hlavného skriptu main.py, odkiaľ budeme ovládať aj objekt calculator. Používateľa sa opýtame na dve čísla, s ktorými bude chcieť počítať. Celú logiku zadávania vstupu od používateľa dáme do bloku try. Teda keď nastane chyba typu ValueError, program skočí do bloku except a vypíše chybu:

from calculator import Calculator

calculator = Calculator()

try:
    a = float(input("Enter the first number: "))
    b = float(input("Enter the second number: "))
except ValueError:
    print("Error: The input is not a number.")

Vždy je najlepšie dávať do bloku try iba tú časť kódu, ktorá môže vyvolať chybu. Ďalej sa odporúča zachytávať určitý typ výnimky. Pri porušení jedného z týchto bodov zvyšujeme šancu, že zachytíme výnimku, s ktorou sme nepočítali, a tak môžeme spôsobiť neočakávané správanie aplikácie.

Zvyšok programu vykonáme vo vetve else, ktorá sa spustí, keď k chybe nedôjde. Necháme si zadať operáciu a podľa nej potom zavoláme danú metódu na objekte calculator. Metóda calculator.divide() môže pri delení nulou vyvolať výnimku, jej volanie teda vložíme do bloku try a v prípade chyby (except) chybu vypíšeme:

from calculator import Calculator

calculator = Calculator()

try:
    a = float(input("Enter the first number: "))
    b = float(input("Enter the second number: "))
except ValueError:
    print("Error: The input is not a number.")
else:
    operation = input("Choose an operation (+, -, *, /): ")

    match operation:
        case "+":
            result = calculator.add(a, b)
        case "-":
            result = calculator.subtract(a, b)
        case "*":
            result = calculator.multiply(a, b)
        case "/":
            try:
                result = calculator.divide(a, b)
            except ZeroDivisionError as e:
                result = "Error: Cannot divide by zero."
        case _:
            result = "Error: Invalid operation."

    print("Result:", result)

Skúsme program spustiť a zadať neplatný vstup:

Konzolová aplikácia
Enter the first number: one
Error: The input is not a number.

A skúsme deliť nulou:

Konzolová aplikácia
Enter the first number: 10
Enter the second number: 0
Choose an operation (+, -, *, /): /
Result: Error: Cannot divide by zero.

raise

Doteraz sme iba zachytávali chyby, ktoré vyvolal samotný Python (napríklad delenie nulou). Občas sa nám však hodí výnimku vyvolať úmyselne, napríklad keď používateľ zadá hodnotu, ktorá je síce technicky platná, ale pre náš program nedáva zmysel. Na to slúži príkaz raise.

Ukážeme si to na metóde triedy Calculator, ktorá bude počítať druhú odmocninu. V Pythone možno odmocniť aj záporné číslo, ale výsledok je potom komplexné číslo, ktoré sme sa rozhodli v našej kalkulačke nepodporovať. Preto sa rozhodneme takýto vstup zakázať a vyvoláme vlastnú výnimku. Doplňme súbor calculator.py o nasledujúcu metódu:

def square_root(self, a):
    if a < 0:
        raise ValueError("The square root of a negative number is not supported")
    return a ** (1 / 2)

Druhú odmocninu technicky vypočítame umocnením čísla na jednu polovicu. Rovnako by sme mohli použiť aj matematickú funkciu sqrt().

Teraz si môžeme v hlavnom programe vyskúšať, ako sa raise správa. Ak si nechcete prepisovať pôvodný main.py, vytvorte si napríklad main_square_root.py a budeme spúšťať tento súbor:

from calculator import Calculator

calculator = Calculator()

try:
    number = float(input("Enter a number to calculate its square root: "))
    result = calculator.square_root(number)
except ValueError as e:
    result = "Error: No number entered or a negative number entered."

print("Result:", result)

Ak zadáme kladné číslo, program bez problémov vypíše odmocninu:

Konzolová aplikácia
Enter a number to calculate its square root: 100
Result: 10.0

Ak zadáme záporné číslo, metóda square_root() pomocou raise vyvolá výnimku ValueError a program ju zachytí v except a vypíše zrozumiteľnú chybovú hlášku:

Konzolová aplikácia
Enter a number to calculate its square root: -1
Result: Error: No number entered or a negative number entered.

Zhrnutie lekcie

Výnimky nám umožňujú ošetriť chyby tak, aby program pri nesprávnom vstupe nespadol, ale zrozumiteľne zareagoval. Rizikový kód zapisujeme do bloku try a konkrétne chyby zachytávame v blokoch except, napríklad ako ValueError alebo ZeroDivisionError. Blok else sa spustí len pri úspešnom priebehu bez chyby a finally prebehne vždy. Vlastnú výnimku môžeme vyvolať príkazom raise, ak zadaná hodnota pre náš program nedáva zmysel.

V nasledujúcej lekcii, Vlastnosti v Pythone, sa budeme zaoberať vlastnosťami čiže gettermi a settermi, ktoré umožnia jednoduchšie nastavovanie a validáciu hodnôt atribútov.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 0x (2.6 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Dekorátory druhýkrát - Parametrické a triedne dekorátory
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Vlastnosti v Pythone
Článok pre vás napísal Adam Straňovský
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se zabývá výukou a vzděláváním dospělých, zejména v oblasti výpočetní techniky, programování a tvorby webových stránek. Ve volném čase se rád věnuje hudbě a hře na kytaru.
Aktivity