2.25. Gestionarea erorilor

Majoritatea problemelor de execuție din Python apar sub formă de excepții – un mod denumit și structurat de a raporta că ceva nu a mers bine. ValueError, TypeError, KeyError, OSError, MemoryError sunt toate exemple; fiecare este o clasă, iar generarea (raising) uneia oprește apelul curent și caută un gestionar în codul înconjurător.

2.25.1. try / except

Încadrează un bloc de cod în try pentru a captura orice excepție pe care o generează:

try:
    n = int(input_text)
except ValueError:
    n = 0

Dacă conversia int(...) eșuează, controlul sare la blocul except în loc să propage eroarea mai departe. Dacă input_text era un șir reprezentând un întreg valid, blocul except este sărit.

Un singur try poate avea mai multe blocuri except, fiecare capturând un tip diferit de eroare:

try:
    value = data[key]
except KeyError:
    value = None
except TypeError:
    value = -1

Python le potrivește în ordine; primul a cărui clasă de excepție se potrivește tratează problema. Capturarea Exception (clasa de bază pentru aproape orice) tratează orice eroare; rezervă aceasta pentru stratul cel mai exterior al unui program, acolo unde alternativa este o blocare.

Atenționare

Un except: simplu (fără clasă după cuvântul-cheie) capturează și KeyboardInterrupt – excepția pe care o trimite IDE-ul atunci când apeși butonul stop pentru a întrerupe un script în execuție. O buclă încadrată într-un except: pass simplu va înghiți întreruperea și va continua să ruleze, neavând nicio altă cale de a opri scriptul decât oprirea și repornirea alimentării.

Preferă except Exception: în locul lui except: simplu atunci când chiar ai nevoie să capturezi pe scară largă. KeyboardInterrupt moștenește din BaseException, nu din Exception, așa că except Exception: lasă butonul stop să funcționeze.

2.25.1.1. Inspectarea excepției

Pentru a citi mesajul atașat unei excepții, denumește-o cu as:

try:
    f = open("data.txt")
except OSError as e:
    print("could not open file:", e)

Variabila legată prin as este validă doar în interiorul blocului except.

2.25.2. else și finally

Un bloc try are două opțiuni suplimentare.

else rulează doar când try s-a finalizat fără a genera o excepție:

try:
    value = compute()
except ValueError:
    print("bad input")
else:
    print("got", value)

Plasarea „ce să faci când a reușit” în else menține blocul try restrâns – în try ar trebui să se afle doar linia care ar putea eșua.

finally rulează la final indiferent de situație – fie că try a reușit, a generat o excepție care a fost tratată, sau a generat o excepție pe cale să se propage:

try:
    do_work()
finally:
    cleanup()
Diagramă de flux care arată cele patru căi posibile prin try / except / else / finally: succesul merge la else apoi la finally; o excepție capturată merge la except apoi la finally; o excepție necapturată merge la finally apoi se propagă.

finally rulează întotdeauna. else rulează doar pe calea fără excepție.

Pentru majoritatea tiparelor de alocare/eliberare, preferă un gestionar de context în locul unei perechi try / finally – resursa însăși își gestionează propria curățare.

2.25.3. Excepții încorporate comune

O scurtă listă a excepțiilor pe care le vei întâlni frecvent:

  • ValueError – tip corect, valoare greșită (bytes([300]) – 300 este tipul corect, dar se află în afara intervalului valid de octeți 0..255).

  • TypeError – tip complet greșit (len(42)).

  • KeyError – cheie lipsă într-un dict.

  • IndexError – index dincolo de sfârșitul unei secvențe.

  • AttributeError – accesarea unui atribut care nu există ("abc".foo).

  • OSError – o eroare de sistem de fișiere sau de I/O.

  • MemoryError – a rămas fără heap. Pe un mediu de execuție cu memorie limitată, acest lucru se poate întâmpla în timpul funcționării normale – nu doar în cazuri patologice.