Blog JSystems - uwalniamy wiedzę!

Szukaj
Animacja try/except - łapanie błędów
try / except - gdy w bloku try wystąpi błąd, sterowanie przeskakuje do except

Dotychczas w wielu sytuacjach spotykaliśmy się z wyjątkami. Przy próbie dzielenia przez zero, przy próbie dostępu do nieistniejącego elementu słownika czy listy. W przypadku pojawienia się wyjątku program przestaje być wykonywany, dlatego warto reagować na pojawiające się wyjątki.

Obsługa wyjątków

Najpierw spróbujmy wywołać jakiś wyjątek:

print(1/0)
print("dalej")

Gdy spojrzymy na konsolę po próbie uruchomienia powyższego kodu, zobaczymy komunikat o pojawieniu wyjątku:

print(1/0)
ZeroDivisionError: division by zero

Słowo "dalej" nie zostało wypisane na konsoli, czyli program został przerwany w momencie pojawienia się wyjątku. Co jednak gdy chcielibyśmy aby w przypadku pojawienia się wyjątku został on obsłużony przez zaplanowany przez nas sposób, a program kontynuował swoje działanie? Tu z pomocą przychodzi nam konstrukcja try-except-finally-else dostępna w Pythonie.

Skorzystajmy z jej podstawowej formy w celu poprawienia powyższego programu:

try:
    print(1/0)
except:
    print("nie zabanglało")
print("dalej")

Tym razem na konsoli nie pojawił się żaden wyjątek, za to zostało wydrukowane słowo "dalej". Powiedzieliśmy Pythonowi "try" - czyli spróbuj zrobić to, a jak się nie uda "except" to zrób to. Wyjątek pojawiający się w instrukcji "print(1/0)" został przechwycony w bloku except i została wykonana zaplanowana przez nas reakcja sprowadzająca się do wyświetlenia stosownego komunikatu. Ponieważ wyjątek został obsłużony program pracował dalej i na konsoli wyświetliło się również "dalej". Gdyby po instrukcji "print(1/0)" znalazły się jeszcze kolejne, nie zostałyby one wykonane.

Prezentowany kod będzie działał dla każdego wyjątku. Możemy także obsługiwać wskazane rodzaje wyjątków:

try:
    print(1/0)
except ZeroDivisionError:
    print("nie można dzielić przez zero!")

Tym razem obsłużyliśmy jedynie wyjątego dzielenia przez zero (ZeroDivisionError). Gdyby kod spowodował pojawienie się innego wyjątku, nie zostałby on obsłużony. Na taką ewentualność też mamy sposób:

try:
    print(1/0)
except ZeroDivisionError:
    print("nie można dzielić przez zero!")
except:
    print("jakiś inny błąd")

Inny błąd zostanie obsłużony instrukcjami pojawiającymi się po drugim wystąpieniu klauzuli "except". To byłaby taka obsługa ogólna dla wszystkich pozostałych wyjątków, którą musimy umieścić zawsze na końcu. Obługiwać wyjątki możemy też zbiorczo dla kilku wybranych rodzajów wyjątów:

try:
    print(1/0)
except(ZeroDivisionError,IOError):
    print("albo to, albo to")

W powyższym przykładzie dla obu wyjątków obsługa sprowadzałaby się do tych samych czynności.

Możemy też zechcieć odebrać komunikat błędu (np. żeby zarejestrować go w logach), a w takim przypadku nadajemy alias:

try:
    print(1/0)
except ZeroDivisionError as e:
    print(e)

Na konsoli zostaje wyświetlone:

division by zero

Może się też tak zdarzyć że będziemy chcieli wykonać jakąś czynność niezależnie od wystąpienia lub nie wyjątku. Wtedy wykorzystujemy klauzulę finally:

try:
    print(1/0)
except:
    print("wyjątek")
finally:
    print("co by się nie działo to ja się uruchamiam")

Istnieje też możliwość zareagowania w sytuacji gdy wyjątek nie wystąpił:

try:
    print("info")
except ValueError:
    print("wyjątek")
else:
    print("nie bylo wyjatku")

Python umożliwia też wywoływanie wyjątków, nawet jeśli taki wyjątek nie wystąpi "naturalnie":

try:
    raise TypeError()
except TypeError:
    print("to było do przewidzenia...")

Grupy wyjątków - except* (Python 3.11 i nowsze)

Czasem w jednej operacji może naraz wystąpić kilka niezależnych błędów - na przykład gdy przetwarzamy wiele zadań i chcemy zebrać wszystkie problemy, a nie zatrzymać się na pierwszym. Od Pythona 3.11 służą do tego grupy wyjątków (ExceptionGroup) i nowa składnia "except*". Gwiazdka oznacza, że łapiemy wszystkie wyjątki danego typu z całej grupy, nawet jeśli w grupie są też inne rodzaje:

try:
    raise ExceptionGroup('kilka problemów naraz', [
        ValueError('zła wartość'),
        TypeError('zły typ'),
        ValueError('druga zła wartość'),
    ])
except* ValueError as eg:
    print(f'Złapane ValueError: {len(eg.exceptions)}')
except* TypeError as eg:
    print(f'Złapane TypeError: {len(eg.exceptions)}')
Złapane ValueError: 2
Złapane TypeError: 1

Każdy blok "except*" dostaje mniejszą grupę zawierającą tylko pasujące wyjątki. To rozwiązanie przydaje się głównie przy współbieżności (na przykład zadania asyncio uruchamiane równolegle), gdzie kilka zadań może zawieść jednocześnie. W codziennym kodzie nadal najczęściej użyjemy zwykłego "except", ale warto wiedzieć, że grupy istnieją.

Dopiski do wyjątku - metoda add_note (Python 3.11 i nowsze)

Od Pythona 3.11 do przechwyconego wyjątku można dołożyć dodatkowy opis metodą "add_note". Notatka pojawi się w komunikacie błędu (traceback), co ułatwia diagnozę bez zmiany typu wyjątku:

try:
    liczba = int('to nie liczba')
except ValueError as e:
    e.add_note('Wartość pochodziła z pliku konfiguracyjnego config.ini')
    raise

Dzięki temu w tracebacku obok standardowego komunikatu "invalid literal for int()" zobaczymy też naszą podpowiedź, skąd wzięła się błędna dana - a to często najważniejsza informacja przy szukaniu przyczyny.

Szkolenie Python od podstaw, przez analizę danych, do machine learning w JSystems

Ten kurs daje Ci solidne podstawy Pythona. Jeśli chcesz pójść dalej i pod okiem trenera dojść od pierwszej linijki kodu do własnego modelu uczenia maszynowego, sprawdź nasze pięciodniowe szkolenie Python od podstaw, przez analizę danych, do machine learning. Pierwsze trzy dni to Python w praktyce: typy i kolekcje, instrukcje warunkowe i pętle, funkcje, moduły i pakiety, pliki tekstowe, usługi sieciowe oraz praca z bazą PostgreSQL. Czwarty dzień to analiza danych w pandas (wczytywanie CSV, TSV i XLS, filtrowanie, agregacje, statystyki) i wizualizacja w Matplotlib, Seaborn oraz Plotly. Piąty dzień to uczenie maszynowe w scikit-learn: regresja liniowa i logistyczna, drzewa decyzyjne, las losowy, XGBoost, walidacja predykcji, dobór hiperparametrów i przeciwdziałanie przeuczeniu. Szkolenie ma terminy gwarantowane, czyli odbywa się niezależnie od wielkości grupy.

Szkolenie Python od podstaw, przez analizę danych, do machine learning

To szkolenie może być dofinansowane dla Ciebie z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Do czego służy konstrukcja try i except w Pythonie?
Pozwala obsłużyć błąd, zamiast przerywać program. Gdy w bloku try wystąpi wyjątek, sterowanie przeskakuje do bloku except, w którym umieszczasz zaplanowaną reakcję. Dzięki temu program może kontynuować działanie mimo napotkanego błędu.
Jak obsłużyć tylko wybrany rodzaj wyjątku?
Po słowie except podajesz nazwę konkretnego wyjątku, na przykład ZeroDivisionError, wtedy blok złapie tylko ten rodzaj. Możesz dodać kolejne bloki except dla innych wyjątków, a ogólny except bez nazwy umieszczasz na końcu, żeby przechwycił wszystkie pozostałe przypadki.
Czym różnią się klauzule finally i else?
Blok finally wykonuje się zawsze, niezależnie od tego, czy wyjątek wystąpił, więc nadaje się do sprzątania. Blok else uruchamia się tylko wtedy, gdy w try nie pojawił się żaden wyjątek. Obie klauzule uzupełniają podstawową konstrukcję try i except.
Do czego służą grupy wyjątków i składnia except gwiazdka?
Od Pythona 3.11 grupy wyjątków (ExceptionGroup) pozwalają zebrać kilka niezależnych błędów naraz, zamiast zatrzymać się na pierwszym. Składnia except z gwiazdką łapie wszystkie wyjątki danego typu z całej grupy. Przydaje się głównie przy współbieżności, na przykład przy zadaniach asyncio.
Jak dodać własny opis do przechwyconego wyjątku?
Od Pythona 3.11 służy do tego metoda add_note, którą wywołujesz na przechwyconym wyjątku. Twoja notatka pojawi się w komunikacie błędu obok standardowego opisu, co ułatwia diagnozę bez zmiany typu wyjątku. Można na przykład zapisać, z jakiego pliku pochodziła błędna dana.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...