Złap mnie, jeśli potrafisz: przewodnik po obsłudze wyjątków w Pythonie

May 09 2023
Odblokuj pełny potencjał Pythona poprzez inteligentne zarządzanie wyjątkami Dla programisty radzenie sobie z wyjątkami jest często postrzegane jako zło konieczne. Jednak opanowanie systemu obsługi wyjątków Pythona może sprawić, że będziesz bardziej wydajnym i skutecznym programistą.

Odblokuj pełny potencjał Pythona dzięki inteligentnemu zarządzaniu wyjątkami

Zdjęcie Cookie the Pom na Unsplash

Jako programista radzenie sobie z wyjątkami jest często postrzegane jako zło konieczne. Jednak opanowanie systemu obsługi wyjątków Pythona może sprawić, że będziesz bardziej wydajnym i skutecznym programistą.

W tym poście na blogu przedstawię szczegółowe wyjaśnienie następujących kwestii:

  • Co to jest obsługa wyjątków?
  • Różnica między ifinstrukcjami a obsługą wyjątków
  • Używanie elsei finallyKlauzule dotyczące właściwego zarządzania błędami
  • Definiowanie niestandardowych wyjątków
  • Najlepsze praktyki dotyczące obsługi wyjątków

obsługa wyjątków to proces pisania kodu w celu przechwytywania i obsługi błędów lub wyjątków, które mogą wystąpić podczas wykonywania programu. Umożliwia to programistom pisanie solidnego kodu, który będzie działał nawet w obliczu nieoczekiwanych zdarzeń lub błędów, zamiast ulegać całkowitemu zawieszeniu.

Kiedy wystąpi wyjątek, Python szuka pasującego programu obsługi wyjątków. Kod obsługi wykona się i podejmie odpowiednie działania, takie jak zarejestrowanie błędu, wyświetlenie komunikatu o błędzie lub próba naprawy po błędzie. Ogólnie rzecz biorąc, obsługa wyjątków pomaga uczynić aplikacje Pythona bardziej niezawodnymi, łatwiejszymi w utrzymaniu i łatwiejszymi do debugowania.

Różnica między ifinstrukcjami a obsługą wyjątków

Podstawowe różnice między ifinstrukcjami a obsługą wyjątków w Pythonie leżą w ich celach i scenariuszach użycia.

Instrukcja ifsłuży jako podstawowy element konstrukcyjny programowania strukturalnego. Ocenia warunek i wykonuje różne bloki kodu w zależności od tego, czy warunek jest prawdziwy, czy fałszywy. Oto przykład:

temperature = int(input("Please enter temperature in Fahrenheit: "))
if temperature > 100:
    print("Hot weather alert! Temperature exceeded 100°F.")
elif temperature >= 70:
    print("Warm day ahead, enjoy sunny skies.")
else:
    print("Bundle up for chilly temperatures.")

Wyjątki służą do sygnalizowania problemów i wskazywania obszarów w kodzie, które wymagają poprawy, debugowania lub dodatkowych środków sprawdzania błędów. Pozwalają Pythonowi z wdziękiem radzić sobie z błędnymi sytuacjami i kontynuować wykonywanie skryptu, zamiast nagle go kończyć.

Rozważmy następujący przykład implementacji obsługi wyjątków w celu lepszego zarządzania potencjalnymi niepowodzeniami związanymi z dzieleniem przez zero:

# Define a function that tries to divide a number by zero
def divide(x, y):
    result = x / y
    return result
# Call the divide function with x=5 and y=0
result = divide(5, 0)
print(f"Result of dividing {x} by {y}: {result}")

Traceback (most recent call last):
  File "<stdin>", line 8, in <module>
ZeroDivisionError: division by zero attempted

Możemy obsłużyć powyższy wyjątek, zawijając wywołanie funkcji „divide” wewnątrz try-exceptbloku w następujący sposób:

# Define a function that tries to divide a number by zero
def divide(x, y):
    result = x / y
    return result
# Call the divide function with x=5 and y=0
try:
    result = divide(5, 0)
    print(f"Result of dividing {x} by {y}: {result}")
except ZeroDivisionError:
    print("Cannot divide by zero.")

Cannot divide by zero.

Więcej informacji o wbudowanych wyjątkach w Pythonie można znaleźć w [2] .

Korzystanie z klauzul Else i Last dla prawidłowego zarządzania błędami

Podczas pracy z wyjątkami w Pythonie zaleca się włączenie klauzul obu elsei finallydo try-exceptbloków. Klauzula elsepozwala określić, co powinno się stać, jeśli nie zostanie zgłoszony żaden wyjątek, podczas gdy klauzula finallyzapewnia, że ​​pewne operacje czyszczenia są zawsze wykonywane niezależnie od tego, czy wystąpił wyjątek [1] [2] .

Rozważmy na przykład scenariusz, w którym chcesz odczytać dane z pliku i wykonać pewne operacje na tych danych. Jeśli podczas odczytu pliku wystąpi wyjątek, możesz chcieć zarejestrować błąd i zatrzymać dalsze przetwarzanie, ale nadal chcesz poprawnie zamknąć plik.

Użycie klauzul elseand finallypozwoliłoby ci właśnie to zrobić - przetwarzać dane normalnie, jeśli nie wystąpi żaden wyjątek, lub odpowiednio obsłużyć wszelkie wyjątki, wciąż zamykając plik na końcu. Bez tych klauzul Twój kod byłby narażony na wycieki zasobów lub niepełną obsługę błędów. W związku z tym odgrywają one istotną rolę w tworzeniu solidnych i niezawodnych programów.

try:
    # Open the file in read mode
    file = open("file.txt", "r")
    print("Successful opened the file")
except FileNotFoundError:
    # Handle missing files
    print("File Not Found Error: No such file or directory")
    exit()
except PermissionError:
    # Handle permission issues
    print("Permission Denied Error: Access is denied")
else:
    # All good, do something with the file data
    content = file.read().decode('utf-8')
    processed_data = process_content(content)
    
# Cleanup after ourselves even if an exception occurred above
finally:
    file.close()

W innym przypadku, gdy w obrębie bloku nie wystąpią żadne wyjątki try, przystępujemy do przetwarzania zawartości pliku w elsegałęzi. Wreszcie operacja czyszczenia zapewniona przez finallyblok zamyka plik niezależnie od tego, czy wyjątek został zgłoszony wcześniej, czy nie [1] .

Przyjmując takie ustrukturyzowane podejście, Twój kod pozostaje uporządkowany i łatwy do śledzenia, jednocześnie uwzględniając potencjalne błędy, które mogą wynikać z interakcji z zewnętrznymi systemami lub danymi wejściowymi.

Definiowanie niestandardowych wyjątków

W Pythonie możesz definiować niestandardowe wyjątki, tworząc podklasy wbudowanych wyjątków, takich jak Exceptionlub dowolna inna klasa, która dziedziczy bezpośrednio z Exception.

Aby to zrobić, musisz utworzyć nową klasę, która dziedziczy z jednego z tych podstawowych wyjątków i dodać atrybuty specyficzne dla twoich potrzeb. Następnie możesz użyć nowo zdefiniowanej klasy wyjątku w całym kodzie, tak jak używałbyś każdej innej wbudowanej klasy wyjątku.

Oto przykład zdefiniowania niestandardowego wyjątku o nazwie InvalidEmailAddress:

class InvalidEmailAddress(ValueError):
    def __init__(self, message):
        super().__init__(message)
        self.msgfmt = message

Możesz zgłosić ten wyjątek za każdym razem, gdy napotkasz nieprawidłowy format adresu e-mail:

def send_email(address):
    if isinstance(address, str) == False:
        raise InvalidEmailAddress("Invalid email address")
# Send email

>>> send_email(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/project/main.py", line 8, in send_email
    raise InvalidEmailAddress("Invalid email address")
InvalidEmailAddress: Invalid email address

Oto kilka najlepszych praktyk związanych z obsługą błędów w Pythonie:

  1. Projektuj z myślą o niepowodzeniach : planuj z wyprzedzeniem, rozważając możliwe awarie i projektując program tak, aby radził sobie z nimi z wdziękiem. Oznacza to przewidywanie przypadków skrajnych i wdrażanie odpowiednich procedur obsługi błędów.
  2. Używaj opisowych komunikatów o błędach : udostępniaj szczegółowe komunikaty o błędach lub dzienniki, które pomogą użytkownikom zrozumieć, co poszło nie tak i dlaczego. Unikaj ogólnych komunikatów o błędach, takich jak „Wystąpił błąd” lub „Stało się coś złego”. Zamiast tego wyświetl przyjazny komunikat, który sugeruje rozwiązania lub podaje linki do dokumentacji. Pamiętaj, aby zachować równowagę między dostarczaniem szczegółowych instrukcji a unikaniem zaśmiecania interfejsu użytkownika zbędnymi treściami.
  3. Zminimalizuj skutki uboczne : zminimalizuj konsekwencje nieudanych działań, izolując problematyczne sekcje kodu za pomocą bloków try-finally lub try-with-resources. Upewnij się, że zadania czyszczenia są zawsze wykonywane niezależnie od wyniku powodzenia lub niepowodzenia.
  4. Dokładnie przetestuj : Przetestuj dokładnie: Upewnij się, że procedury obsługi wyjątków zachowują się poprawnie w różnych scenariuszach, uruchamiając kompleksowe testy.
  5. Regularnie refaktoryzuj : Refaktoryzuj podatne na błędy segmenty kodu, aby poprawić ich niezawodność i wydajność. Zachowaj modułową i luźno powiązaną bazę kodu, pozwalając niezależnym częściom na niezależną ewolucję bez negatywnego wpływu na inne.
  6. Rejestruj ważne zdarzenia: śledź interesujące zdarzenia w aplikacji, rejestrując je w pliku lub na wyjściu konsoli. Pomaga to szybko diagnozować problemy bez konieczności przeglądania dużej ilości nieustrukturyzowanych dzienników.

Pisanie kodu obsługującego błędy jest integralną częścią tworzenia oprogramowania, szczególnie podczas pracy z Pythonem, ponieważ umożliwia programistom tworzenie bardziej niezawodnych i niezawodnych aplikacji. Postępując zgodnie ze standardami branżowymi i najlepszymi praktykami, programiści mogą skrócić czas debugowania, zapewnić jakość kodu i zapewnić lepsze wrażenia użytkownika.

Zasoby

[1]https://docs.python.org/3/tutorial/errors.html

[2]https://www.geeksforgeeks.org/python-exception-handling/