2.25. Obsługa błędów¶
Większość problemów wykonania w Pythonie ujawnia się jako wyjątki – nazwany, ustrukturyzowany sposób zgłaszania, że coś poszło nie tak. ValueError, TypeError, KeyError, OSError, MemoryError to wszystko przykłady; każdy z nich jest klasą, a zgłoszenie jednego z nich zatrzymuje bieżące wywołanie i szuka procedury obsługi w otaczającym kodzie.
2.25.1. try / except¶
Otocz blok kodu instrukcją try, aby przechwycić każdy zgłoszony przez niego wyjątek:
try:
n = int(input_text)
except ValueError:
n = 0
Jeśli konwersja int(...) się nie powiedzie, sterowanie przeskakuje do bloku except zamiast propagować błąd dalej. Jeśli input_text był poprawnym łańcuchem liczby całkowitej, blok except jest pomijany.
Pojedynczy try może mieć kilka bloków except, z których każdy przechwytuje inny rodzaj błędu:
try:
value = data[key]
except KeyError:
value = None
except TypeError:
value = -1
Python dopasowuje je po kolei; problem obsługuje pierwszy, którego klasa wyjątku pasuje. Przechwytywanie Exception (klasy bazowej dla niemal wszystkiego) obsługuje każdy błąd; zarezerwuj to dla najbardziej zewnętrznej warstwy programu, gdzie alternatywą jest awaria.
Ostrzeżenie
Goły except: (bez klasy po słowie kluczowym) przechwytuje także KeyboardInterrupt – wyjątek wysyłany przez IDE, gdy naciśniesz przycisk stop, aby przerwać działający skrypt. Pętla otoczona gołym except: pass połknie przerwanie i będzie działać dalej, nie pozostawiając sposobu na zatrzymanie skryptu poza wyłączeniem i włączeniem zasilania.
Gdy naprawdę musisz przechwytywać szeroko, preferuj except Exception: zamiast gołego except:. KeyboardInterrupt dziedziczy po BaseException, a nie po Exception, więc except Exception: pozostawia działający przycisk stop.
2.25.1.1. Badanie wyjątku¶
Aby odczytać komunikat dołączony do wyjątku, nazwij go za pomocą as:
try:
f = open("data.txt")
except OSError as e:
print("could not open file:", e)
Zmienna powiązana przez as jest ważna tylko wewnątrz bloku except.
2.25.2. else i finally¶
Blok try ma dwa opcjonalne dodatki.
else wykonuje się tylko wtedy, gdy try zakończył się bez zgłoszenia wyjątku:
try:
value = compute()
except ValueError:
print("bad input")
else:
print("got", value)
Umieszczenie „co zrobić, gdy się powiodło” w else utrzymuje blok try wąskim – do try należy tylko wiersz, który może zawieść.
finally wykonuje się na końcu bez względu na wszystko – niezależnie od tego, czy try się powiódł, zgłosił wyjątek i został on obsłużony, czy też zgłosił go i ma się on właśnie propagować:
try:
do_work()
finally:
cleanup()
finally wykonuje się zawsze. else wykonuje się tylko na ścieżce bez wyjątku.¶
W przypadku większości wzorców pozyskania/zwolnienia zasobu preferuj menedżer kontekstu zamiast pary try / finally – sam zasób zarządza wtedy swoim sprzątaniem.
2.25.3. Częste wyjątki wbudowane¶
Krótka lista wyjątków, na które będziesz często trafiać:
ValueError– właściwy typ, błędna wartość (bytes([300])– 300 jest właściwego typu, ale leży poza poprawnym zakresem bajtu 0..255).TypeError– całkowicie błędny typ (len(42)).IndexError– indeks poza końcem sekwencji.AttributeError– dostęp do nieistniejącego atrybutu ("abc".foo).OSError– awaria systemu plików lub wejścia/wyjścia.MemoryError– zabrakło sterty. W środowisku uruchomieniowym o ograniczonej pamięci może się to zdarzyć podczas normalnej pracy – nie tylko w skrajnych przypadkach.