Python - Rukovanje izuzecima pomoću izjava try, except i finally


Izuzeci u Pythonu

Python ima mnogo ugrađenih izuzetaka koji se pojavljuju kada vaš program naiđe na grešku (nešto u programu pođe po zlu). Kada se pojave ovi izuzeci, Python interpreter zaustavlja trenutni proces i prosljeđuje ga pozivajućem procesu dok se njime ne rukuje. Ako se ne riješi, program će se srušiti.

Na primjer, razmotrimo program u kojem imamo funkciju A koja poziva funkciju B, koja zauzvrat poziva funkciju C. Ako se izuzetak dogodi u funkciji C, ali se njime ne rukuje u C, izuzetak prolazi u B, a zatim u A. Ako se nikad ne riješi, prikazuje se poruka o grešci i naš program iznenada prestaje sa radom.



Hvatanje izuzetaka u Pythonu

U Pythonu se s izuzecima može postupati pomoću naredbe try. Kritična operacija koja može stvoriti izuzetak smještena je unutar klauzule try. Kod koji obrađuje izuzetke napisan je u klauzuli except. Tako možemo odabrati koje ćemo operacije izvršiti nakon što uhvatimo izuzetak. Evo jednostavnog primjera.

#import module sys da biste dobili vrstu izuzetka
import sys

randomList = ['a', 0, 2]

for entry in randomList:
    try:
        print("Unos je", entry)
        r = 1/int(entry)
        break
    except:
        print("Oops!", sys.exc_info()[0], "occurred.")
        print("Sljedeći unos.")
        print()
print("Recipročno od", entry, "je", r)

U ovom programu prolazimo kroz vrijednosti liste randomList. Kao što je prethodno spomenuto, dio koji može izazvati izuzetak smješten je unutar bloka try. Ako se ne dogodi izuzetak, blok except se preskače i nastavlja se normalni protok (za zadnju vrijednost). Ali ako se dogodi bilo kakav izuzetak, hvata ga blok except (prva i druga vrijednost).

Ovdje ispisujemo ime izuzetka pomoću funkcije exc_info() unutar sys modula. Možemo vidjeti da uzroci ValueError i 0 uzrokuju ZeroDivisionError. Budući da se svaki izuzetak u Pythonu nasljeđuje iz osnovne klase Exception, gornji primjer možemo izvršiti i na sljedeći način:

# import module sys da biste dobili vrstu izuzetka
import sys

randomList = ['a', 0, 2]

for entry in randomList:
    try:
        print("Unos je", entry)
        r = 1/int(entry)
        break
    except Exception as e:
        print("Oops!", e.__class__, "occurred.")
        print("Sljedeći unos.")
        print()
print("Recipročno od", entry, "je", r)

Ovaj program ima isti izlaz kao i gornji program.



Hvatanje specifičnih izuzetaka u Pythonu

U gornjem primjeru nismo spomenuli nijedan specifičan izuzetak u klauzuli except. Ovo nije dobra praksa programiranja, jer će uhvatiti sve izuzetke i na svaki način rješavati svaki slučaj na isti način. Možemo odrediti koje bi izuzetke trebala uhvatiti klauzula except. Klauzula try može imati bilo koji broj osim klauzula za obradu različitih izuzetaka, međutim, samo jedna će se izvršiti u slučaju da se dogodi izuzetak. Koristimo skup vrijednosti da odredimo višestruke izuzetke u klauzuli except. Evo primjera pseudo koda.

try:
   # uradi nešto
   pass

except ValueError:
   # obrađivanje izuzetaka ValueError
   pass

except (TypeError, ZeroDivisionError):
    # obrađivanje višestrukih izuzetaka
    # TypeError i ZeroDivisionError
   pass

except:
   # rukovanje sa svim ostalim izuzecima
   pass


Povećavanje izuzetaka u Pythonu

U programiranju u Pythonu, izuzeci se pojavljuju kada se greške pojave tokom izvođenja. Takođe možemo ručno podizati izuzetke pomoću ključne riječi rise. Izborno možemo prosljediti vrijednosti izuzetku kako bismo pojasnili zašto je taj izuzetak pokrenut.

>>> podizanje KeyboardInterrupt
Traceback (most recent call last):
...
KeyboardInterrupt

>>> raise MemoryError("Ovo je argument")
Traceback (most recent call last):
...
MemoryError: Ovo je argument

>>> try:
...     a = int(input("Unesite pozitivan cijeli broj (integer): "))
...     if a <= 0:
...         raise ValueError("To nije pozitivan broj!")
... except ValueError as ve:
...     print(ve)
...    
Unesite pozitivan cijeli broj (integer): -2
To nije pozitivan broj!


Python try sa else klauzulom

U nekim situacijama možda ćete htjeti pokrenuti određeni blok koda ako se blok koda unutar pokušaja pokrene bez ikakvih grešaka. U tim slučajevima možete koristiti opcionalnu ključnu riječ else sa iskazom try.

Pogledajmo primjer:

# program za ispis obostranih parnih brojeva

try:
    num = int(input("Unesite broj: "))
    assert num % 2 == 0
except:
    print("Neparan broj!")
else:
    reciprocal = 1/num
    print(reciprocal)


Python try...finally

Izjava try u Pythonu može imati neobavezujuću klauzulu. Ova se klauzula izvršava bez obzira na sve i obično se koristi za oslobađanje vanjskih resursa. Na primjer, možemo biti povezani s udaljenim centrom podataka putem mreže ili raditi s datotekom ili grafičkim korisničkim interfejsom (GUI).

U svim tim okolnostima moramo očistiti resurs prije nego što se program zaustavi bez obzira da li se uspješno pokrenuo ili ne. Te se radnje (zatvaranje datoteke, GUI ili prekid veze s mrežom) izvode u finally klauzuli kako bi se zagarantovalo izvršenje. Evo primjera operacija datoteka radi ilustracije ovoga.

try:
   f = open("test.txt",encoding = 'utf-8')
   # izvoditi operacije datoteka
finally:
   f.close()

Ova vrsta konstrukcije osigurava da je datoteka zatvorena čak i ako se tokom izvođenja programa dogodi izuzetak.