Czym są wyjątki w Pythonie?
Błędy w Pythonie dzielimy na dwa rodzaje, tj. błędy składniowe i wyjątki. Błędy składniowe to problemy w programie, z powodu których program zatrzyma wykonywanie. Z kolei wyjątki, występują w określonych okolicznościach działania programu i zmieniają jego normalny przebieg.
Różnica pomiędzy błędem składniowym a wyjątkiem
Błąd składniowy, jak sama nazwa wskazuje, to błąd związany z zapisem w kodzie sprzecznym ze składnią Pythona. Prowadzi to do zakończenia programu. Weźmy poniższy przykład:
i = 0
while i < 100:
print(i)
i ++= 1
Widzimy, że w linii 4 znajduje się błąd składniowy, ponieważ zamiast i += 1
programista zapisał błędnie i ++= 1
. W efekcie tego błędu, po uruchomieniu programu zobaczymy błąd:
SyntaxError: invalid syntax
Wyjątki są zgłaszane, gdy działanie programu powoduje błąd, jednak nie jest on spowodowany błędem składniowym. Przykładem może być próba otwarcie nieistniejącego pliku:
fh = open("testfile", "r")
Zapis w kodzie jest prawidłowy, jednak gdy plik nie istnieje, to podczas uruchomienia programu otrzymamy:
FileNotFoundError: [Errno 2] No such file or directory: 'testfile'
Wyjątki zgłaszane przez program możemy obsługiwać, dzięki czemu program jest odporny, na różnego rodzaju sytuacje niepożądane.
Zgłaszanie wyjątków i łapanie (try i except)
Instrukcje try
i except
służą do przechwytywania i obsługi wyjątków w Pythonie. Podstawowa składnia bloku try...except
wygląda następująco:
try:
# kod, który może rzucać wyjątek
except:
# kod, który się uruchamia, gdy wyjątek wystąpi
Weźmy przykład dzielenia dwóch liczb:
wynik = licznik/mianownik
Jak wiadomo, operacja dzielenia przez 0 nie jest możliwa. Pomimo tego, że składnia kodu jest prawidłowa, to po uruchomieniu programu dostaniemy:
ZeroDivisionError: division by zero
Program możemy zabezpieczyć przed niepożądaną operacją dzielenia przez 0 stosując blok try...catch
w następujący sposób:
try:
licznik = 5
mianownik = 0
wynik = licznik/mianownik
print(wynik)
except:
print("Błąd. Nie można dzielić przez 0")
Dzięki temu działanie programu nie zostanie zatrzymane. Zamiast błędu otrzymamy komunikat “Błąd. Nie można dzielić przez 0”.
Rodzaje wyjątków w Pythonie
W Pythonie istnieje kilka wbudowanych typów wyjątków. Oto niektóre z nich:
- KeyError: wyjątek jest zgłaszany, gdy w słowniku nie znaleziono klucza.
- ValueError: wyjątek jest zgłaszany, gdy funkcja lub metoda jest wywoływana z nieprawidłowym argumentem, lub danymi wejściowymi.
- TypeError: wyjątek jest zgłaszany, gdy operacja lub funkcja zostanie zastosowana do obiektu niewłaściwego typu.
Pełną lista wbudowanych wyjątków znajdziemy pod adresem:
https://docs.python.org/3/library/exceptions.html
Łapanie określonych wyjątków w Pythonie
W poniższym kodzie zaimplementowano dwa bloki catch
. Pierwszy z nich przechwytuje wyjątek ZeroDivisionError
, a drugi IndexError
.
try:
licznik = 5
liczby = [1, 4, 1, 4]
mianownik = liczby[2]
print(licznik/mianownik)
mianownik = liczby[5]
print(licznik/mianownik)
except ZeroDivisionError:
print("Błąd. Nie można dzielić przez 0")
except IndexError:
print("Przekroczono rozmiar listy")
Ponieważ w linii 6 program odwołuje się do elementu o indeksie 5, który nie istnieje, zostanie rzucony wyjątek IndexError
, który zostanie przechwycony przez odpowiedni blok catch
. W efekcie po uruchomieniu otrzymamy:
5.0
Przekroczono rozmiar listy
Blok try…finally
W Pythonie blok finally
jest wykonywany zawsze, niezależnie od tego, czy wyjątek wystąpił, czy nie.
try:
licznik = 5
mianownik = 0
wynik = licznik/mianownik
print(wynik)
except:
print("Błąd. Nie można dzielić przez 0.")
finally:
print("To jest blok finally.")
Wynik:
Błąd. Nie można dzielić przez 0.
To jest blok finally.