Exceptii
La nivelul unei aplicatii Python pot fi intalnite doua tipuri de erori: erori de sintaxa si exceptii. Erorile de sintaxa, sau erorile de parsare, sunt determinate de nerespectarea sintaxei. In secventa de mai jos, lipsa caracterului : dupa instructiunea while determina aparitia unei astfel de erori.
>>> while True print("hello") File "", line 1 while True print("hello") ^ SyntaxError: invalid syntax>
Exceptiile reprezinta situatii care apar in timpul rularii unui program si care determina oprirea acestuia. De exemplu, pot fi generate exceptii in urmatoarele cazuri:
• impartirea unui numar la zero ZeroDivisionError;
• deschiderea unui fisier care nu exista FileNotFoundError;
• accesarea unei variabile care nu a fost definita NameError;
• includerea unui modul care nu exista ModuleNotFoundError;
• realizarea de operatii cu valori de tipuri diferite TypeError.
>>> 2 * (3/0) Traceback (most recent call last): File "<stdin>", line 1, in ZeroDivisionError: division by zero
>>> import modul Traceback (most recent call last): File "<stdin>", line 1, in ModuleNotFoundError: No module named 'modul'
>>> '3' + 2 Traceback (most recent call last): File "<stdin>", line 1, in TypeError: can only concatenate str (not "int") to str
Exceptiile ofera un mecanism eficient de identificare si rezolvare a erorilor care apar in timpul executiei unui program. In limbajul Python exista posibilitatea tratarii exceptiilor prin stabilirea unei cai alternative de continuare a executiei programului.
La aparitia unei exceptii sau erori de rulare (run-time error) este creat automat un obiect de tip exceptie. De asemenea, exista si posibilitatea generarii exceptiilor prin intermediul instructiunii raise.
In limbajul Python, toate exceptiile sunt instante ale unor clase derivate din BaseException. Clasele corespunzatoare exceptiilor sunt definite prin intermediul unei ierarhii de clase.
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError | +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError | +-- UnboundLocalError +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning
In plus, fata de beneficiile organizationale evidente, utilizarea acestei ierarhii este utila in tratarea exceptiilor. Tratarea unei exceptii de un anumit tip presupune si tratarea exceptiilor derivate din acest tip de exceptie.
Tratarea exceptiilor
Limbajul Python ofera o solutie eficienta de rezolvare a exceptiilor care apar intr-un program prin intermediul mecanismului de tratare a exceptiilor. Implementarea acestei solutii se face folosind constructii de tipul try .. except .. finally.
try: # instructiuni urmarite except Exceptie: # tratare exceptii de tip Exceptie ... except: # tratare pentru restul exceptiilor else: # instructiuni executate daca nu sunt generate exceptii finally: # instructiuni executate neconditionat
Blocul try este utilizat pentru a delimita instructiunile care vor fi urmarite in vederea identificarii exceptiilor. Daca este lansata o exceptie, se suspenda executia restului de instructiuni din blocul try si sunt verificate blocurile except. Exceptia este tratata de primul bloc except care contine tipul exceptiei sau un supertip al acesteia.
try: | |
a = [1, 2, 3] | |
print(a[3]) | |
except LookupError: | |
print("Index out of bound error.") | |
else: | |
print("Success!") |
Netratarea unei exceptii va determina in cele din urma oprirea programului si afisarea unui mesaj corespunzator.
Daca nu este generata o exceptie si este prezent blocul else sunt executate instructiunile de la nivelul acestui bloc, dupa care se executa urmatoarea instructiune de dupa instructiunea try.
try: | |
numar = int(input("Introdu un intreg pozitiv: ")) | |
if numar <= 0: | |
raise ValueError("Acesta nu este un numar pozitiv!") | |
except ValueError as e: | |
print(e) | |
else: | |
print("Multumim!") |
Se poate observa ca instructiunile din interiorul blocului finally sunt executate intotdeauna. Instructiunile de la nivelul blocului finally au in vedere, in general, eliberarea resurselor externe.
try: | |
f = open('fisier.txt', 'r') | |
except IOError: | |
print("Fisierul nu exista!") | |
else: | |
print("Fisierul a fost identificat!") | |
print("Acesta are {} linii.".format(len(f.readlines()))) | |
f.close() | |
finally: | |
print("Secventa finalizata!") |
Definirea de exceptii utilizator
Limbajul Python ofera posibilitatea definirii propriilor exceptii, pentru a pune in evidenta conditiile de eroare care nu au fost prevazute in ierarhia exceptiilor predefinite. Se recomanda derivarea de noi exceptii (de utilizator) pornind de la clasele de exceptii predefinite.
Clasa exceptie trebuie sa fie derivata, direct sau indirect, din clasa Exception. Se recomanda crearea unei clase de baza pentru exceptiile definite la nivelul unui modul.
class Eroare(Exception): | |
"Clasa de baza pentru exceptii de utilizator" | |
pass | |
class FonduriInsuficiente(Eroare): | |
"Exceptie generata cand soldul unui cont este mai mic decat suma solicitata" | |
pass | |
class Cont: | |
def __init__(self, numar, sold): | |
self.numar = numar | |
self.sold = sold | |
def __str__(self): | |
return "Contul {} are un sold de {} RON.".\ | |
format(self.numar, round(self.sold, 2)) | |
def depune(self, suma): | |
self.sold += suma | |
def retrage(self, suma): | |
try: | |
if self.sold >= suma: | |
self.sold -= suma | |
else: | |
necesar = suma - self.sold | |
raise FonduriInsuficiente("Fonduri insuficiente! Necesar {} RON.".\ | |
format(round(necesar, 2))) | |
except FonduriInsuficiente as e: | |
print(e) | |
if __name__ == "__main__": | |
c = Cont("SV523BTV74635643", 500.34) | |
# Contul SV523BTV74635643 are un sold de 500.34 RON. | |
print(c) | |
c.depune(20.12) | |
# Fonduri insuficiente! Necesar 502.63 RON. | |
c.retrage(1023.09) |
Generarea unei exceptii se realizeaza prin intermediul instructiunii raise. Instructiunea raise poate fi utilizata fara argument intr-un bloc except pentru a rearunca exceptia prinsa de acel bloc.
Contul SV523BTV74635643 are un sold de 500.34 RON. Fonduri insuficiente! Necesar 502.63 RON.