Drzewo wyjątków w Pythonie
Język Python 3 definiuje 63 wbudowane wyjątki, a wszystkie one tworzą hierarchię w kształcie drzewa, chociaż to drzewo jest nieco dziwne, ponieważ jego korzeń znajduje się na górze.
Niektóre z wbudowanych wyjątków są bardziej ogólne (zawierają inne wyjątki), podczas gdy inne są całkowicie konkretne (reprezentują tylko siebie). Można powiedzieć, że im bliżej korzenia znajduje się wyjątek, tym bardziej jest on ogólny (abstrakcyjny). Z kolei wyjątki znajdujące się na końcach gałęzi (możemy nazywać je liśćmi) są konkretne.
def wyswietl_drzewko(klasa, zagniezdzenie = 0): if zagniezdzenie > 1: print(" |" * (zagniezdzenie - 1), end="") if zagniezdzenie > 0: print(" +---", end="") print(klasa.__name__) for podklasa in klasa.__subclasses__(): wyswietl_drzewko(podklasa, zagniezdzenie +1) wyswietl_drzewko(BaseException)
Wyjątki w Pythonie
Istnieją co najmniej dwie możliwości, że coś może „pójść źle” w kodzie poniżej.
- Ponieważ użytkownik może wprowadzić całkowicie dowolny łańcuch znaków, nie ma gwarancji, że łańcuch ten może zostać przekształcony w wartość zmiennoprzecinkową – jest to pierwsza słabość kodu;
- druga to fakt, że funkcja sqrt() skończy się niepowodzeniem, jeśli otrzyma ujemny argument.
import math x = float(input("Wprowadz x: ")) y = math.sqrt(x) print("pierwiastek kwadratowy z", x, "rowna sie", y)
Poniższy kod wyglądać powinien następująco:
import math
x = float(input("Wprowadz x: ")) y = math.sqrt(x) print("pierwiastek kwadratowy z", x, "rowna sie", y)
Za każdym razem, gdy twój kod próbuje zrobić coś złego/głupiego/nieodpowiedzialnego/szalonego/niewykonalnego, język Python robi dwie rzeczy:
- zatrzymuje twój program;
- tworzy specjalny rodzaj danych, zwany wyjątkiem.
Obie te czynności są nazywane zgłaszaniem wyjątku. Możemy powiedzieć, że język Python zawsze zgłasza wyjątek (lub że wyjątek został zgłoszony), gdy nie ma pojęcia, co zrobić z twoim kodem.
Co dzieje się dalej?
- zgłoszony wyjątek czeka, aż ktoś go zauważy i zajmie się nim;
- jeśli nikt się nie zajmie zgłoszonym wyjątkiem, program zostanie przymusowo zakończony, i zobaczysz komunikat o błędzie wysłany do konsoli przez język Python;
- jeśli jednak ktoś zajmie się wyjątkiem i odpowiednio go obsłuży, zawieszony program zostanie wznowiony, a jego wykonywanie będzie kontynuowane.
Język Python dostarcza efektywnych narzędzi, które pozwalają obserwować wyjątki, identyfikować i obsługiwać je sprawnie. Jest to możliwe dzięki temu, że wszystkie potencjalne wyjątki mają swoje jednoznaczne nazwy, więc możesz je kategoryzować i odpowiednio reagować.
Wyjątek ZeroDivisionError:
pierwsza_liczba = int(input("Wprowadź pierwszą liczbę: ")) druga_liczba = int(input("Wprowadź drugą liczbę: ")) if druga_liczba!= 0: print(pierwsza_liczba / druga_liczba) else: print("Ta operacja nie może być wykonana.") print("KONIEC.")
pierwsza_liczba = int(input("Wprowadź pierwszą liczbę: ")) druga_liczba = int(input("Wprowadź drugą liczbę: ")) try: print(pierwsza_liczba / druga_liczba) except: print("Ta operacja nie może być wykonana.") print("KONIEC.")
W pierwszym kroku język Python próbuje wykonać wszystkie instrukcje umieszczone pomiędzy twierdzeniami try: i except:;
jeśli nie wystąpi błąd wykonania i wszystkie instrukcje zostaną wykonywane poprawnie, przechodzi on do punktu za ostatnią linią bloku except:, a wykonanie bloku uważa za zakończone;
Jeśli coś pójdzie nie tak w bloku try: i except:, wykonanie natychmiastowo przeskakuje z bloku do pierwszej instrukcji znajdującej się za słowem kluczowym except:; oznacza to, że niektóre instrukcje z bloku mogą być po cichu pomijane.
Wyjątek ValueError:
try: x = int(input("Wprowadź liczbę: ")) y = 1 / x print(y) except ZeroDivisionError: print("Nie możesz dzielić przez zero.") except ValueError: print("Musisz wpisać wartość całkowitą.") except: print("Oj, coś poszło nie tak...") print("KONIEC.")
- jeśli wpiszesz dowolny łańcuch znaków nie będący liczbą całkowitą, zobaczysz:
Musisz wpisać wartość całkowitą.
- jeśli naciśniesz Ctrl-C, gdy program czeka na dane wejściowe użytkownika (co powoduje wyjątek o nazwie KeyboardInterrupt), program wyświetli:
Oj, coś poszło nie tak...
Obsługa wyjątków w Pythonie – cd
def odwrotnosc(n): try: n = 1 / n except ZeroDivisionError: print("Dzielenie zakonczone niepowodzeniem") return None else: print("Wszystko przebieglo pomyslnie") return n print(odwrotnosc(2)) print(odwrotnosc(0))
Kod zostaje wykonany wtedy, gdy żaden wyjątek nie został wywołany przez część, zawierającą słowo try:. Można stwierdzić, że po try: może zostać wykonana tylko jedna gałąź kodu – albo ta zaczynająca się od except (nie zapominaj, że kod może zawierać więcej niż jedną gałąź tego typu) albo ta, która zaczyna się słowem else.
Uwaga: gałąź else: musi znaleźć się po ostatniej gałęzi except.
def odwrotnosc(n): try: n = 1 / n except ZeroDivisionError: print("Dzielenie zakonczone niepowodzeniem") n = None else: print("Wszystko przebieglo pomyslnie") finally: print("Do widzenia") return n print(odwrotnosc(2)) print(odwrotnosc(0))
Blok finally jest zawsze wykonywany, bez względu na to, co stało się wcześniej, nawet przy wywołaniu wyjątku i bez znaczenia, czy został on obsłużony, czy nie.
Asertacja – wyrażenie assert
- Analizuje wyrażenie;
- jeśli wyrażenie zwraca wartość
True
, lub niezerową wartość liczbową, lub niepusty łańcuch znaków, lub jakąkolwiek wartość inną niżNone
, nie zrobi niczego więcej; - w przeciwnym razie, automatycznie i natychmiast zgłosi wyjątek o nazwie AssertionError (w tym przypadku mówimy, że instrukcja assert się nie powiodła)
- zgłoszenie wyjątku AssertionError zabezpiecza twój kod przed wygenerowaniem nieprawidłowych wyników i wyraźnie pokazuje charakter błędu;
- instrukcje assert nie zastępują wyjątków ani nie potwierdzają danych – są ich dodatkami.
import math x = float(input("Wprowadz liczbe: ")) assert x >= 0.0 x = math.sqrt(x) print(x)
Program działa bezbłędnie, jeśli wprowadzisz poprawną wartość liczbową większą lub równą zero; w przeciwnym razie zatrzyma się i wyświetli następujący komunikat:
Traceback (most recent call last):
File ".main.py", line 4, in
assert x >= 0.0
AssertionError
Zadanie:
Twoim zadaniem jest napisanie funkcji zdolnej do wprowadzenia wartości w postaci liczby całkowitej oraz do sprawdzenia, czy wprowadzana liczba mieści się w określonym przedziale.
def readint(prompt, min, max): # # tu wpisz swój kod # v = readint("Podaj liczbę od -10 do 10: ", -10, 10) print("Liczba to:", v)