https://docs.python.org/3/library/exceptions.html
https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement
Zalety wyjątków opartych na klasach.
# Nowe podejście - wyjątek to klasa wywiedziona z klasy Exception. # Do nazwy dajemy suffix "Error", o ile wyjątek to błąd. # Dla ostrzeżeń w nazwie dodajemy "Warning". class MyError(Exception): """Warto stworzyć wiersz dokumentujący.""" pass raise MyError("message") # wywołanie wyjątku exception = MyError("a", "b") # instancja wyjątku # W atrybucie args znajduje się krotka argumentów konstruktora domyślnego. print(exception.args) # ('a', 'b') # Domyślnie str() wyświetla zawartość atrybutu args. print(exception) # ('a', 'b')
try: raise MyError("message") # instancja #except MyError: except MyError as exception: print("przechwycenie MyError") print(exception.args)
Jeżeli wyjątek został wyzwolony z argumentami, to w instancji wyjątku są domyślnie przechowywane jako krotka w atrybucie args. Dla wygody klasa Exception definiuje metodę __str__() wyświetlającą argumenty, dzięki czemu nie musimy bezpośrednio odwoływać się do atrybutu args.
Można zdefiniować własny konstruktor wyjątku (__init__). Podobnie można określić własny sposób wyświetlania wyjątku (__str__).
class MyError(Exception): def __init__(self, value): # nasz konstruktor wyjątku self.value = value def __str__(self): # zmiana sposobu wyświetlania wyjątku return repr(self.value) try: raise MyError(2*2) # instancja wyjątku except MyError as exception: # Py2.6+, Py3 # except MyError, exception: # Py2.6- # Python 3 interpretuje przecinek jako oznaczający krotkę. # Obiekt exception jest to zgłoszona instancja klasy MyError. print("mam wyjątek, value {}".format(exception.value)) print("mam wyjątek, value {}".format(exception)) # jw, bo jest __str__ import sys print("Zgłoszono wyjątek {}".format(sys.exc_info()))
Ostatnio zgłoszony i przechwycony wyjątek jest dostępny ogólnie, jako drugi argument krotki wyników wywołania sys.exc_info(), (typ, wartość, ślad), (type, value, traceback). Jeżeli żaden wyjątek nie jest obsługiwany, to zwracana krotka ma postać (None, None, None).
Do jawnego wywoływania wyjątków służy instrukcja raise.
# Składnia. # Zgłoszenie instancji klasy [najbardziej typowe]. # raise instancja_wyjątku raise IndexError() raise IndexError("message") # Zgłoszenie obiektu klasy - instancja klasy zostanie utworzona automatycznie. # raise klasa_wyjątku raise IndexError # Ponowne zgłoszenie ostatniego wyjątku. raise # Zgłoszenie nowego wyjątku z wykorzystaniem kontekstu starego wyjątku. raise new_exception from old_exception # Py3 raise new_exception from None # Dla wbudowanych wyjątków mamy równoważne formy. raise KeyError raise KeyError() # Utworzenie instancji wyjątku z wyprzedzeniem. exception = IndexError() raise exception
Instrukcja assert jest składniowym skrótem dla często wykorzystywanego w debugowaniu wzorca z instrukcją raise. Najczęściej wykorzystuje się ją do weryfikowania warunków programu w czasie jego tworzenia (tzw. sytuacje niemożliwe). Pomaga wcześnie wykrywać pewne błędy w programie. Ponadto assert działa jako dokumentacja dla innych deweloperów czytających kod, pozwala lepiej zrozumieć stan systemu w danym punkcie programu.
Nie powinno się używać assert do obsługi błędów użytkownika, czy innych błędów pojawiających się w trakcie pracy programu.
Instrukcję assert można usunąć z kodu bajtowego skompilowanego programu, jeżeli w wierszu poleceń Pythona użyjemy opcji -O (python -O main.py), tym samym optymalizując program.
# Składnia podstawowa. assert expression # Równoważny kod. if __debug__: if not expression: raise AssertionError()
# Składnia rozszerzona. assert expression1, expression2 # Równoważny kod. if __debug__: if not expression1: raise AssertionError(expression2) # expression2 to zwykle komunikat (string)
>>> x = 1 >>> assert x == 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError >>> assert x == 0, "x have to be zero" Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: x have to be zero >>>
Kiedy except z instrukcji try wymienia klasę nadrzędną, przechwytuje instancje tej klasy, a także instancje wszystkich jej klas podrzędnych.
Warto korzystać z wyjątków wbudowanych i rzucać je w sytuacjach podobnych do tych, w jakich robi to interpreter. Nie ma jednak mechanizmów zabezpieczających przed rzuceniem nieodpowiedniego wyjątku przez kod użytkownika. Można dziedziczyć z wyjątków wbudowanych, ale należy unikać dziedziczenia wielobazowego ze względu na specyficzne zarządzanie pamięcią w wyjątkach i możliwe konflikty.
W Pythonie 3.11 pojawiły się 'grupy wyjątków' (exception groups), które są używane kiedy trzeba jednocześnie rzucić wiele niepowiązanych ze sobą wyjątków. Do stworzenia grupy wyjatków wykorzystuje się dziedziczenie z klasy 'ExceptionGroup'.
>>> import exceptions # Py2.6+ >>> help(exceptions) # drzewo klas
>>> import builtins # Py3, built-in functions, exceptions, and other objects >>> help(builtins)
BaseException +-- BaseExceptionGroup (Py3.11) +-- SystemExit # rzucany przez sys.exit() +-- KeyboardInterrupt # rzucany po naciśnięciu Ctrl+C lub Delete +-- GeneratorExit # rzucany przez generator.close() i coroutine.close() +-- Exception # klasa bazowa dla wyjątków wbudowanych i wyjątków użytkownika +-- StopIteration +-- StandardError | +-- ArithmeticError | +-- AssertionError | +-- AttributeError | +-- NameError | +-- SyntaxError | +-- IndentationError | +-- TypeError | +-- ValueError | +-- ImportError | +-- MemoryError | +-- RuntimeError | +-- NotImplementedError | +-- EnvironmentError | +-- IOError | +-- OSError | +-- LookupError | +-- IndexError | +-- KeyError | +-- ExceptionGroup [BaseExceptionGroup] (Py3.11) | +-- ... +-- Warning +-- DeprecationWarning [PEP 387] +-- UserWarning +-- SyntaxWarning +-- RuntimeWarning +-- ...
Wybrane wyjątki.