Jak wychwycić wiele wyjątków w Pythonie: prosty przewodnik

Photo of author

By maciekx

Efektywne zarządzanie wyjątkami w Pythonie jest kluczowe dla tworzenia stabilnych i niezawodnych aplikacji, które zapewniają użytkownikom pozytywne doświadczenia. W niniejszym artykule przeanalizujemy, jak w elegancki sposób obsługiwać wiele wyjątków w ramach jednego bloku `try/except` w Pythonie, co prowadzi do bardziej zwięzłego i łatwiejszego w utrzymaniu kodu.

Czym są wyjątki w Pythonie?

W środowisku Pythona, wyjątki pełnią rolę mechanizmu komunikacyjnego między różnymi fragmentami kodu. Pozwalają one na poinformowanie o napotkaniu nieoczekiwanego problemu, z którym dany fragment programu nie jest w stanie samodzielnie sobie poradzić.

W praktyce, gdy kod natrafi na sytuację wyjątkową, generuje (zgłasza) wyjątek. Inna część programu, która potrafi obsłużyć taki wyjątek, przejmuje kontrolę i właściwie reaguje na zaistniały błąd.

Brak odpowiedniej obsługi wyjątków prowadzi do nieoczekiwanego zatrzymania działania programu. Dlatego właściwe zarządzanie nimi jest niezbędne dla zapewnienia stabilności aplikacji i uniknięcia niepożądanych awarii.

Artykuł ten zakłada znajomość podstawowych koncepcji dotyczących zgłaszania i obsługi wyjątków, które zostały omówione w innych materiałach na temat `try/except` w Pythonie.

Dlaczego warto obsługiwać wiele wyjątków w Pythonie?

  • Redukcja powtarzalności kodu: Obsługa kilku wyjątków w jednym bloku `except` eliminuje potrzebę duplikowania kodu obsługi, co czyni program bardziej przejrzystym i prostszym w modyfikacji.
  • Poprawa wydajności: Dzięki grupowaniu obsługi podobnych wyjątków, program musi tylko raz sprawdzić typ błędu, zamiast robić to wielokrotnie.

Obsługa wielu wyjątków

Pojęcie przechwytywania wielu wyjątków odnosi się do sytuacji, w której różnorodne błędy są obsługiwane za pomocą jednego bloku `except`. Python umożliwia obsługę każdego z wyjątków w osobnych blokach `except`. Jednakże, jeżeli zamierzamy podjąć te same działania dla różnych typów błędów, wygodniej jest obsłużyć je w jednym bloku `except`. W dalszej części artykułu przedstawimy praktyczne przykłady, jak to zrobić.

#1. Obsługa różnych wyjątków w osobnych blokach

Rozważmy program, który pobiera od użytkownika dwie liczby i wykonuje na nich operację dzielenia. W takim przypadku, możemy oczekiwać wystąpienia różnych rodzajów wyjątków, w zależności od wprowadzonych danych. Konkretnie, interesują nas `ValueError` oraz `ZeroDivisionError`.

`ValueError` pojawia się, gdy użytkownik wprowadzi wartość, której nie da się przekonwertować na liczbę całkowitą. `ZeroDivisionError` jest zgłaszany, gdy dzielnik (druga wprowadzona liczba) wynosi zero. W obu tych przypadkach chcielibyśmy wyświetlić informację „Wprowadzono niepoprawną wartość”.

Poniższy kod demonstruje, jak obsłużyć te błędy za pomocą osobnych bloków `except`:


try:
    dividend = int(input('Wprowadź pierwszą liczbę: '))
    divisor = int(input('Wprowadź drugą liczbę: '))
    quotient = dividend / divisor
    print(quotient)
except ValueError as e:
    print("Wprowadzono niepoprawną wartość")
except ZeroDivisionError as e:
    print("Wprowadzono niepoprawną wartość")
except Exception as e:
    print("Coś poszło nie tak")

Uruchomienie powyższego kodu z tekstem, który nie jest liczbą, skutkuje następującym rezultatem:

A wprowadzenie zera jako drugiej liczby spowoduje wyświetlenie tego komunikatu:

Kod działa prawidłowo, ale można zauważyć powtarzalność w blokach `except` dla `ValueError` i `ZeroDivisionError`. Narusza to zasadę DRY (Don’t Repeat Yourself), która mówi, że należy unikać duplikowania kodu.

Aby tego uniknąć, możemy połączyć te dwa bloki `except` w jeden, obsługujący kilka wyjątków jednocześnie, co eliminuje powtórzenia.

#2. Obsługa wielu wyjątków w jednym bloku `except`

Aby obsłużyć wiele wyjątków w jednym bloku `except`, należy podać krotkę z nazwami wszystkich typów błędów, które chcemy przechwycić. Poniższy przykład pokazuje, jak obsłużyć `ValueError` i `ZeroDivisionError` w ramach jednego bloku:


try:
    dividend = int(input('Wprowadź pierwszą liczbę: '))
    divisor = int(input('Wprowadź drugą liczbę: '))
    quotient = dividend / divisor
    print(quotient)
except (ValueError, ZeroDivisionError) as e:
    print("Wprowadzono niepoprawną wartość")
except Exception as e:
    print("Coś poszło nie tak")

Jest to znacznie lepsze rozwiązanie niż poprzednie. Właśnie na tym polega obsługa wielu wyjątków. Powyższy kod działa tak samo jak wcześniej. Testując go z poprzednimi przykładami, powinien dać identyczne rezultaty:

#3. Identyfikacja przechwyconego wyjątku

Powyższy kod wykonuje pierwszy blok `except` niezależnie od tego, czy został wywołany błąd `ValueError`, czy `ZeroDivisionError`. W pewnych sytuacjach może być konieczne wykonanie odrębnego kodu w zależności od rodzaju przechwyconego błędu.

W takim przypadku, musimy najpierw zidentyfikować, jaki błąd został wywołany, aby móc podjąć odpowiednie działanie.

Aby określić typ przechwyconego wyjątku, można użyć konstrukcji `if/else` wewnątrz bloku `except`. Przykład:


try:
    dividend = int(input('Wprowadź pierwszą liczbę: '))
    divisor = int(input('Wprowadź drugą liczbę: '))
    quotient = dividend / divisor
    print(quotient)
except (ValueError, ZeroDivisionError) as e:
    print("Wprowadzono niepoprawną wartość")
    if isinstance(e, ValueError):
        print('Błąd wartości')
    else:
        print('Błąd dzielenia przez zero')
except Exception as e:
    print("Coś poszło nie tak")

W tym przykładzie, oprócz wypisania ogólnego komunikatu o błędzie, sprawdzamy, jakiego typu błąd został przechwycony i wypisujemy bardziej szczegółową informację. Ponowne uruchomienie programu z tym kodem pokaże odpowiednie dodatkowe komunikaty.

Kiedy stosować obsługę wielu wyjątków?

Zazwyczaj, obsługa wielu wyjątków w jednym bloku jest idealna, gdy chcemy wykonać ten sam kod dla grupy podobnych wyjątków, które mogą wystąpić. Przykłady:

  • Nieudane żądania sieciowe: Jeżeli żądanie sieciowe nie powiedzie się z różnych powodów, możemy poinformować użytkownika o niemożności połączenia z serwerem.
  • Problemy z bazą danych: Różne błędy połączenia z bazą danych mogą być obsługiwane w ten sam sposób.
  • Operacje wejścia/wyjścia plików: Błędy związane z operacjami na plikach, takie jak brak uprawnień lub brak miejsca na dysku, mogą być obsługiwane w podobny sposób.

Podsumowanie

W tym artykule omówiliśmy, jak połączyć wiele bloków `except` w jeden, poprzez jednoczesne przechwytywanie kilku wyjątków. Dzięki temu kod staje się bardziej przejrzysty i łatwiejszy w utrzymaniu. Zachęcamy również do zapoznania się z artykułem na temat projektów dla początkujących programistów w Pythonie, które warto wypróbować.


newsblog.pl