3.1 Przechwytywanie wyjątków
Nie mówilibyśmy tyle o wyjątkach, gdybyśmy mieli tylko na nie patrzeć. Wyjątki to specjalne obiekty, z którymi może pracować twój program w Pythonie. Obsługa wyjątków to ważny aspekt programowania, który pozwala poprawić niezawodność i stabilność programów.
W Pythonie do przechwytywania i obsługi wyjątków używamy konstrukcji try
, except
, else
i finally
. Te konstrukcje pozwalają na przechwytywanie błędów, które występują podczas wykonywania programu i podjęcie odpowiednich działań.
Konstrukcja try-except
Konstrukcja try-except
służy do przechwytywania i obsługi wyjątków. Blok try
zawiera kod, który może wywołać wyjątek, a blok except
zawiera kod, który zostanie wykonany w przypadku wystąpienia wyjątku.
Przykład:
try:
result = 10 / 0
except ZeroDivisionError:
print("Błąd: dzielenie przez zero.")
Jeśli w kodzie wewnątrz bloku try
wystąpi wyjątek ZeroDivisionError
, zostanie on przechwycony przez blok except
i wykona się kod z wywołaniem print()
.
Obsługa wielu wyjątków
Możesz obsługiwać kilka typów wyjątków, wskazując je w oddzielnych blokach except
.
try:
result = int("abc")
except ZeroDivisionError:
print("Błąd: dzielenie przez zero.")
except ValueError:
print("Błąd: niepoprawna wartość.")
Przechwytywanie wszystkich wyjątków
Jeśli chcesz przechwycić wszystkie wyjątki, możesz użyć bloku except
bez wskazywania konkretnego typu wyjątku. Jednak nie jest to zalecane, ponieważ może to utrudnić debugowanie i ukryć ważne błędy.
try:
result = 10 / 0
except:
print("Wystąpił błąd.")
3.2 Operatory else
i finally
Oprócz operatorów try
i except
, są jeszcze dwa opcjonalne: else
i finally
. Teraz opowiem o nich trochę więcej.
Konstrukcja try-except-else
Blok else
jest używany do wykonania kodu, jeśli w bloku try
nie wystąpiły żadne wyjątki.
try:
result = 10 / 2
except ZeroDivisionError:
print("Błąd: dzielenie przez zero.")
else:
print(f"Wynik: {result}")
Konstrukcja try-except-finally
Blok finally
zawiera kod, który zostanie wykonany niezależnie od tego, czy wystąpił wyjątek, czy nie. Jest to przydatne do zwolnienia zasobów lub wykonania operacji końcowych.
try:
result = 10 / 0
except ZeroDivisionError:
print("Błąd: dzielenie przez zero.")
finally:
print("Ten blok wykonuje się zawsze.")
Pełny przykład: try-except-else-finally
Przykład:
try:
result = 10 / 2
except ZeroDivisionError:
print("Błąd: dzielenie przez zero.")
else:
print(f"Wynik: {result}")
finally:
print("Ten blok wykonuje się zawsze.")
3.3 Przykład try-except-else-finally
Zastanówmy się nad jakimś dużym realnym przykładem. Na przykład, próbujemy odczytać dane z pliku na dysku — co może być prostsze?
file = open("file.txt", "r")
content = file.read()
print(content)
Co może pójść nie tak? Na przykład, wszystko:
- Plik może być nieobecny. Mógł zostać przypadkowo usunięty, niezapisany, albo twój program w ogóle wykonuje się na innym komputerze, gdzie go nigdy nie było.
- Błąd odczytu pliku. Twój program nie ma do niego dostępu, bo znajduje się w katalogu, do którego potrzebne są prawa administratora.
- Inny program teraz zapisuje do tego pliku i nie można go odczytać — ma monopolistyczny dostęp do pliku.
Mało ci? W takim razie nie zapomnij, że niezależnie od tego, w którym kroku wystąpił błąd podczas pracy z plikiem, musisz go „zamknąć”, aby system operacyjny zwolnił zasoby przydzielone do pracy z tym plikiem.
Więc rzeczywisty kod będzie wyglądał mniej więcej tak:
try:
file = open("non_existent_file.txt", "r")
content = file.read()
except FileNotFoundError:
print("Błąd: plik nie znaleziony.")
except IOError:
print("Błąd: błąd wejścia-wyjścia.")
else:
print(content)
finally:
if 'file' in locals() and not file.closed:
file.close()
print("Plik zamknięty.")
Witamy w prawdziwym świecie, gdzie musisz napisać kod nie tylko dla „scenariusza roboczego”, ale także dla wszystkich możliwych scenariuszy, które mogą pójść nie tak.
Spokojnie, to nie jest tak straszne, jak się wydaje. Trzeba tylko rozumieć, czym są warunki brzegowe (corner cases
) i na czas dodawać sprawdzanie standardowych błędów. Resztę zrobią za ciebie nowoczesne frameworki.
GO TO FULL VERSION