Mikuláš je tu! Získaj 90 % extra kreditov ZADARMO s promo kódom CERTIK90 pri nákupe od 1 199 kreditov. Len do nedele 7. 12. 2025! Zisti viac:
NOVINKA: Najžiadanejšie rekvalifikačné kurzy teraz s 50% zľavou + kurz AI ZADARMO. Nečakaj, táto ponuka dlho nevydrží! Zisti viac:

1. diel - Výnimky v Pythone

V tomto kurze Pythonu sa budeme venovať práci so súbormi. Než však začneme zapisovať a čítať, mali by sme vyriešiť, ako ošetriť chybové stavy programu, ktorých pri práci so súbormi bude veľa.

V našom programe môže často dôjsť k chybe. Tým nemyslím chybe z dôvodu, že bol program funkčne zle napísaný, takýmto chybám sa môžeme vyvarovať. Všeobecne ide najmä o chyby, ktoré zapríčinili tzv. vstupno/výstupné operácie. V anglickej literatúre sa hovorí o input/output alebo skrátene o IO. Ide napr. o vstup používateľa z konzoly, zo súboru, výstup do súboru, na tlačiareň a podobne. V zásade platí, že tu figuruje používateľ, ktorý nám môže zadať nezmyselný vstup, neexistujúci alebo nevalidný súbor, odpojiť tlačiareň a podobne. My však nenecháme program spadnúť s chybou, naopak budeme zraniteľné miesta v programe ošetrovať a na danú skutočnosť používateľa upozorníme.

Aktívne ošetrenie chýb

Prvú možnosť ošetrenia chýb nazývame ako aktívna. V programe zmapujeme všetky zraniteľné miesta a ošetríme ich podmienkami. Ako učebnicový príklad sa spravidla používa delenie nulou. Predstavme si program, ktorý používa triedu Mathematics, ktorá má metódu divide(). Trieda by mohla vyzerať napr. takto:

class Mathematics():

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

Teraz triedu použijeme takýmto spôsobom:

print("Enter the dividend and the divisor to calculate the result:")
a = int(input())
b = int(input())
print(Mathematics().divide(a, b))

Ak teraz programu používateľ zadá čísla 12 a 0, program spadne s chybou, pretože nulou nemožno deliť. Aktívne chybu ošetríme jednoduchou podmienkou v programe:

print("Enter the dividend and the divisor to calculate the result:")
a = int(input())
b = int(input())
if b != 0:
    print(Mathematics().divide(a, b))
else:
    print("You cannot divide by zero.")

Teraz si musíme pri každom použití metódy teda strážiť, či do druhého parametra nevkladáme nulu. Predstavte si, že by metóda brala 10 parametrov a používali sme ju v programe niekoľkokrát. Určite by bolo veľmi zložité ošetrovať všetky použitia tejto metódy.

Riešením by mohlo byť vložiť kontrolu priamo do metódy. Máme tu však nový problém: Akú hodnotu vrátime, keď bude 2. parameter nulový? Potrebujeme hodnotu, z ktorej spoznáme, že výpočet neprebehol správne. To je však problém, keď zvolíme napr. nulu, nepoznáme, či napr. 0/12 je chybný výpočet alebo nie. Nevieme, či 0 znamená výsledok alebo chybu. Ani zápornými číslami si nepomôžeme. Parsovanie hodnôt je 2. klasický príklad zraniteľného vstupu od používateľa. Ďalšie sú súborové operácie, kde súbor nemusí existovať, nemusíme naň mať práva, môže sa s ním práve pracovať a podobne.

Pasívne ošetrenie chýb

Najmä, keď je operácia zložitejšia a bolo by príliš náročné ošetrovať všetky možné chybové stavy, nastupujú výnimky, tzv. pasívne ošetrenie chýb. Nás totiž vôbec nemusí zaujímať vnútorná logika v metóde, ktorú voláme. Pokúsime sa nebezpečnú časť kódu spustiť v "chránenom režime". Tento režim je nepatrne pomalší a líši sa tým, že ak dôjde k chybe, máme možnosť ju odchytiť a zabrániť pádu programu. O chybe tu hovoríme ako o výnimke. Využívame na to tzv. try-except bloky:

try:
    pass
except:
    pass

Do bloku try umiestnime nebezpečnú časť kódu. Ak nastane v bloku try chyba, jeho vykonávanie sa preruší a program prejde do bloku except. Ak všetko prebehne v poriadku, try sa vykoná celý a except sa preskočí. Vyskúšajme si situáciu na našom predchádzajúcom príklade:

try:
    print(Mathematics().divide(a, b))
except:
    print("An error occurred while dividing.")

Kód je jednoduchší v tom, že nemusíme ošetrovať všetky zraniteľné miesta a premýšľať, čo všetko by sa mohlo pokaziť. Nebezpečný kód iba obalíme blokom try a všetky chyby sa zachytia v except. Samozrejme do bloku try-except umiestnime len to nevyhnutné, nie celý program :)

Teraz teda už vieme, ako ošetriť situácie, keď používateľ zadáva nejaký vstup, ktorý by mohol vyvolať chybu. Nemusí ísť len o súborové operácie, výnimky majú veľmi širokú oblasť použitia. Dokážeme náš program napísať tak, aby sa nedal používateľom jednoducho zhodiť.

Použitie výnimiek pri práci so súbormi

Ako už bolo povedané, súborové operácie môžu vyvolať mnoho výnimiek, preto sa súbory vždy pracujeme v bloku try-except. Existuje aj niekoľko ďalších konštrukcií, ktoré môžeme pri výnimkách využívať.

Blok finally

Do bloku try-except môžeme pridať ešte 3. blok a to finally. Ten sa spustí vždy, či už k výnimke došlo alebo nie. Predstavte si nasledujúcu metódu na uloženie nastavení:

def saveSettings():
    try:
        f = open("file.dat", "w")
        f.write("Some settings...")
        f.close() # we need to close the file handler
    except:
        print("An error has occurred while writting to the file.")

Metóda sa súbor pokúsi otvoriť a zapísať doň nejaké nastavenia. Otvorený súbor musíme opäť uzavrieť. Pri chybe vypíše hlášku do konzoly. Vypisovať chyby priamo v metóde je však škaredé, to napokon už vieme, metódy a objekty by všeobecne mali vykonávať len logiku a komunikáciu s používateľom obstaráva ten, kto ich volá. Vracajme teda True/False podľa toho, či sa operácia podarila alebo nie:

def saveSettings():
    try:
        f = open("file.dat", "w")
        f.write("Some settings...")
        return True
    except:
        return False
    f.close()

Na prvý pohľad to vyzerá, že sa súbor vždy uzavrie. Celý kód je však v nejakej metóde, v ktorej voláme return. Ako vieme, return ukončí metódu a nič za ním sa už nevykoná.

Súbor by tu vždy zostal otvorený a uzavretie by sa už nevykonalo. Následkom by bolo, že by bol potom súbor neprístupný. Ak vložíme zatvorenie súboru do bloku finally, vykoná sa vždy. Python si pamätá, že blok try-except obsahoval finally a zavolá finally blok aj po opustení bloku except alebo try:

def saveSettings():
    try:
        f = open("file.dat", "w")
        f.write("Some settings...")
        return True
    except:
        return False
    finally:
        f.close()

Blok except by bolo najlepšie úplne vynechať a nechať metódu, aby výnimku pokojne vyvolala. Budeme počítať s tým, že sa s výnimkou vysporiada ten, kto metódu zavolal, nie metóda sama. Je to tak lepšie, ušetríme návratovú hodnotu metódy (ktorú je potom možné použiť pre niečo iné) a kód sa nám zjednoduší:

def saveSettings():
    try:
        f = open("file.dat", "w")
        f.write("Some settings...")
    finally:
        f.close()

Súbor sa v kóde vyššie vždy zavrie, a to aj keď sa pri zápise niečo nepodarí, možno dôjde miesto na médiu. Metódu by sme teraz volali takto:

try:
    saveSettings()
except:
    print("Unable to save settings.")

Teraz si ukážeme, ako celú situáciu ešte viac zjednodušiť. Použijeme konštrukciu with.

Konštrukcia with

Python umožňuje značne zjednodušiť prácu s inštanciami tried na čítanie a zápis do súborov alebo všeobecne tried, ktoré potrebujú vykonávať akékoľvek upratovacie práce. Vyššie uvedený blok môžeme zapísať pomocou notácie with, ktorá nahrádza bloky try a finally. Obrovskou výhodou je, že blok finally Python vygeneruje sám a sám zaistí, aby daná inštancia súbor uzavrela. Metóda saveSettings() by teda vyzerala s pomocou with takto:

def saveSettings():
    with open("file.dat", "w") as f:
        f.write(object)

Vidíme, že sa kód extrémne zjednodušil, aj keď robí v podstate to isté. Pri volaní metódy opäť použijeme blok tryexcept.

Nezabudnite, že with nahrádza iba try-finally, nie except!. Metódu, v ktorej sa používa with, musíme rovnako volať v bloku try-except.

Teraz sme dospeli presne tam, kam som chcel. Na všetky manipulácie so súbormi totiž budeme v nasledujúcich lekciách používať konštrukciu with. Kód bude jednoduchší a nikdy sa nám nestane, že by sme súbor zabudli zavrieť.

K výnimkám sa ešte raz vrátime, ukážeme si, ako odchytávať len niektoré typy výnimiek, ktoré hotové triedy výnimiek môžeme v našich programoch používať a tiež ako vytvoriť výnimku vlastnú. Teraz som však chcel vysvetliť len potrebné minimum pre prácu so súbormi a nie vám zbytočne pliesť hlavu zložitými konštrukciami :)

V nasledujúcej lekcii, Úvod do práce so súbormi v Pythone, sa pozrieme, ako to funguje s právami na zápis do súborov v systéme Windows a vyskúšame si niekoľko prvých súborových operácií.


 

Všetky články v sekcii
Práca so súbormi v Pythone
Preskočiť článok
(neodporúčame)
Úvod do práce so súbormi v Pythone
Článok pre vás napísal MQ .
Avatar
Užívateľské hodnotenie:
76 hlasov
Používám hlavně Python a zajímám se o Deep Learning a vše kolem.
Aktivity