Błędy (errors) i wyjątki (exceptions) to sytuacje, które przerywają normalne wykonanie programu. Bez odpowiedniej obsługi program po prostu się „wysypie” i zakończy działanie.
Dlaczego ważna jest obsługa błędów?
- Program nie kończy działania przy błędzie
- Możesz reagować na błędy (np. prosić użytkownika o poprawne dane)
- Lepsze doświadczenie użytkownika
- Łatwiejsze debugowanie
- Profesjonalny kod produkcyjny
Przykład bez obsługi błędu:
# Program się wysypie jeśli plik nie istnieje
with open("nieistniejacy.txt") as file:
content = file.read()
# FileNotFoundError - program kończy działanie
Z obsługą błędu:
# Program kontynuuje działanie
try:
with open("nieistniejacy.txt") as file:
content = file.read()
except FileNotFoundError:
print("Plik nie istnieje, tworzę nowy")
with open("nieistniejacy.txt", "w") as file:
file.write("Nowa zawartość")
Struktura try-except
Podstawowa składnia
try:
# Kod, który może wywołać błąd
ryzykowna_operacja()
except:
# Kod wykonywany gdy wystąpi błąd
obsluga_bledu()
Pełna struktura
try:
# Spróbuj wykonać ten kod
kod_ktory_moze_wywolac_blad()
except TypBledu:
# Wykonaj gdy wystąpi konkretny błąd
obsluga_bledu()
else:
# Wykonaj TYLKO jeśli NIE było błędu
kod_gdy_sukces()
finally:
# Wykonaj ZAWSZE (bez względu na błędy)
sprzatanie()
Kolejność:
try– zawsze jako pierwszeexcept– jeden lub więcejelse– opcjonalnie, tylko jeśli nie było błędufinally– opcjonalnie, wykonuje się zawsze
Podstawowe typy błędów
FileNotFoundError – brak pliku
# Błąd: próba otwarcia nieistniejącego pliku
with open("nieistniejacy.txt") as file:
content = file.read()
# FileNotFoundError: [Errno 2] No such file or directory: 'nieistniejacy.txt'
Obsługa:
try:
with open("nieistniejacy.txt") as file:
content = file.read()
except FileNotFoundError:
print("Plik nie istnieje!")
KeyError – brak klucza w słowniku
# Błąd: próba dostępu do nieistniejącego klucza
slownik = {"imie": "Jan", "wiek": 25}
miasto = slownik["miasto"]
# KeyError: 'miasto'
Obsługa:
slownik = {"imie": "Jan", "wiek": 25}
try:
miasto = slownik["miasto"]
except KeyError:
print("Klucz 'miasto' nie istnieje")
miasto = "Nieznane"
IndexError – indeks poza zakresem
# Błąd: próba dostępu do nieistniejącego indeksu
lista = ["Python", "Java", "C++"]
jezyk = lista[5]
# IndexError: list index out of range
Obsługa:
lista = ["Python", "Java", "C++"]
try:
jezyk = lista[5]
except IndexError:
print("Indeks poza zakresem listy")
ValueError – nieprawidłowa wartość
# Błąd: konwersja niepoprawnej wartości
wiek = int("dwadzieścia")
# ValueError: invalid literal for int() with base 10: 'dwadzieścia'
Obsługa:
try:
wiek = int(input("Podaj wiek: "))
except ValueError:
print("To nie jest liczba!")
wiek = 0
TypeError – nieprawidłowy typ
# Błąd: dodawanie string + int
tekst = "Python"
wynik = tekst + 5
# TypeError: can only concatenate str (not "int") to str
Obsługa:
tekst = "Python"
try:
wynik = tekst + 5
except TypeError:
print("Nie można dodać liczby do tekstu")
wynik = tekst + str(5)
ZeroDivisionError – dzielenie przez zero
# Błąd: dzielenie przez 0
wynik = 10 / 0
# ZeroDivisionError: division by zero
Obsługa:
try:
wynik = 10 / 0
except ZeroDivisionError:
print("Nie można dzielić przez zero!")
wynik = None
Przechwytywanie konkretnych błędów
ŹLE – ogólny except
# ŹLE - łapie WSZYSTKIE błędy
try:
with open("plik.txt") as file:
content = file.read()
slownik = {"klucz": "wartość"}
print(slownik["nieistniejacy"])
except:
print("Jakiś błąd") # Który? Nie wiadomo!
Problemy:
- Nie wiesz jaki błąd wystąpił
- Trudno debugować
- Możesz ukryć poważne błędy
- Nie możesz różnie reagować na różne błędy
DOBRZE – konkretne except
# DOBRZE - konkretne błędy
try:
with open("plik.txt") as file:
content = file.read()
slownik = {"klucz": "wartość"}
print(slownik["nieistniejacy"])
except FileNotFoundError:
print("Plik nie istnieje")
except KeyError as e:
print(f"Klucz {e} nie istnieje w słowniku")
Wiele except
Możesz mieć wiele bloków except dla różnych błędów.
try:
liczba = int(input("Podaj liczbę: "))
wynik = 100 / liczba
print(f"Wynik: {wynik}")
except ValueError:
print("To nie jest liczba!")
except ZeroDivisionError:
print("Nie można dzielić przez zero!")
except KeyboardInterrupt:
print("\nPrzerwano przez użytkownika")
Przypisanie błędu do zmiennej
try:
slownik = {"imie": "Jan"}
print(slownik["nazwisko"])
except KeyError as error:
print(f"Błąd: brak klucza '{error}'")
# Błąd: brak klucza 'nazwisko'
Inne przykłady:
try:
plik = open("nieistniejacy.txt")
except FileNotFoundError as e:
print(f"Szczegóły błędu: {e}")
try:
wynik = int("abc")
except ValueError as e:
print(f"Błąd konwersji: {e}")
Jeden except dla wielu błędów
# Obsługa wielu błędów tym samym kodem
try:
# Kod ryzykowny
operacja()
except (ValueError, TypeError, KeyError) as e:
print(f"Wystąpił błąd: {e}")
Blok else
Blok else wykonuje się TYLKO gdy w try NIE było błędu.
try:
with open("plik.txt") as file:
content = file.read()
except FileNotFoundError:
print("Plik nie istnieje")
else:
# Wykonuje się TYLKO gdy plik został poprawnie otwarty
print("Zawartość pliku:")
print(content)
Przykład – walidacja danych
try:
wiek = int(input("Podaj wiek: "))
except ValueError:
print("To nie jest liczba!")
else:
# Wykonuje się tylko gdy konwersja się powiodła
if wiek >= 18:
print("Jesteś pełnoletni")
else:
print("Jesteś niepełnoletni")
Blok finally
Blok finally wykonuje się ZAWSZE, niezależnie czy był błąd czy nie.
try:
plik = open("dane.txt", "w")
plik.write("Dane")
except IOError:
print("Błąd zapisu")
else:
print("Zapis udany")
finally:
# ZAWSZE zamknij plik (czy był błąd czy nie)
plik.close()
print("Plik zamknięty")
Typowe zastosowania finally:
- Zamykanie plików
- Zamykanie połączeń z bazą danych
- Zwalnianie zasobów
- Sprzątanie po operacji
Przykład – finally zawsze się wykona
try:
print("Try")
raise ValueError("Błąd!")
except ValueError:
print("Except - złapano błąd")
else:
print("Else - nie wykona się (był błąd)")
finally:
print("Finally - zawsze się wykona")
Wynik:
Try
Except - złapano błąd
Finally - zawsze się wykona
Wywoływanie własnych błędów – raise
Możesz ręcznie wywołać błąd używając słowa kluczowego raise.
Podstawowa składnia
raise TypBledu("Komunikat błędu")
Przykład – walidacja wzrostu
def oblicz_bmi(waga, wzrost):
"""Oblicza BMI z walidacją danych."""
if wzrost > 3:
raise ValueError("Wzrost człowieka nie przekracza 3 metrów!")
if wzrost <= 0:
raise ValueError("Wzrost musi być większy od 0!")
if waga <= 0:
raise ValueError("Waga musi być większa od 0!")
bmi = waga / (wzrost ** 2)
return bmi
# Użycie
try:
wynik = oblicz_bmi(70, 3.5)
except ValueError as e:
print(f"Błąd: {e}")
# Błąd: Wzrost człowieka nie przekracza 3 metrów!
Przykład – funkcja z walidacją
def podziel(a, b):
"""Dzieli dwie liczby z walidacją."""
if not isinstance(a, (int, float)):
raise TypeError("Pierwszy argument musi być liczbą")
if not isinstance(b, (int, float)):
raise TypeError("Drugi argument musi być liczbą")
if b == 0:
raise ZeroDivisionError("Nie można dzielić przez zero")
return a / b
# Użycie
try:
wynik = podziel(10, 0)
except ZeroDivisionError as e:
print(f"Błąd: {e}")
Re-raise – ponowne wywołanie błędu
try:
wynik = 10 / 0
except ZeroDivisionError:
print("Logowanie błędu...")
raise # Ponownie wywołaj ten sam błąd
Przykłady praktyczne
Przykład 1: Bezpieczny input liczby
def pobierz_liczbe(komunikat):
"""Pobiera liczbę od użytkownika z walidacją."""
while True:
try:
liczba = float(input(komunikat))
return liczba
except ValueError:
print("To nie jest liczba! Spróbuj ponownie.")
# Użycie
wiek = pobierz_liczbe("Podaj wiek: ")
print(f"Twój wiek: {wiek}")
Przykład 2: Kalkulator z obsługą błędów
def kalkulator():
"""Prosty kalkulator z obsługą błędów."""
try:
a = float(input("Pierwsza liczba: "))
b = float(input("Druga liczba: "))
operator = input("Operator (+, -, *, /): ")
if operator == "+":
wynik = a + b
elif operator == "-":
wynik = a - b
elif operator == "*":
wynik = a * b
elif operator == "/":
if b == 0:
raise ZeroDivisionError("Nie można dzielić przez zero!")
wynik = a / b
else:
raise ValueError(f"Nieznany operator: {operator}")
print(f"Wynik: {wynik}")
except ValueError as e:
print(f"Błąd wartości: {e}")
except ZeroDivisionError as e:
print(f"Błąd dzielenia: {e}")
except Exception as e:
print(f"Nieoczekiwany błąd: {e}")
kalkulator()
Przykład 3: Bezpieczne otwieranie pliku
def wczytaj_plik(nazwa):
"""Bezpiecznie wczytuje plik."""
try:
with open(nazwa, 'r', encoding='utf-8') as plik:
return plik.read()
except FileNotFoundError:
print(f"Plik {nazwa} nie istnieje")
return None
except PermissionError:
print(f"Brak uprawnień do pliku {nazwa}")
return None
except Exception as e:
print(f"Nieoczekiwany błąd: {e}")
return None
# Użycie
zawartosc = wczytaj_plik("dane.txt")
if zawartosc:
print(zawartosc)
Przykład 4: Słownik z domyślnymi wartościami
def pobierz_wartosc(slownik, klucz, domyslna=None):
"""Pobiera wartość ze słownika z obsługą błędów."""
try:
return slownik[klucz]
except KeyError:
print(f"Klucz '{klucz}' nie istnieje, zwracam wartość domyślną")
return domyslna
# Użycie
dane = {"imie": "Jan", "wiek": 25}
miasto = pobierz_wartosc(dane, "miasto", "Warszawa")
print(f"Miasto: {miasto}") # Miasto: Warszawa
Przykład 5: Lista z bezpiecznym dostępem
def bezpieczny_dostep(lista, indeks):
"""Bezpieczny dostęp do elementu listy."""
try:
return lista[indeks]
except IndexError:
print(f"Indeks {indeks} poza zakresem (0-{len(lista)-1})")
return None
except TypeError:
print("Lista jest None lub indeks nie jest liczbą")
return None
# Użycie
owoce = ["jabłko", "banan", "gruszka"]
owoc = bezpieczny_dostep(owoce, 5)
print(owoc) # None
Przykład 6: Przechwyć błędy w funkcji make_pie
Problem:
fruits = ["Apple", "Pear", "Orange"]
def make_pie(index):
fruit = fruits[index]
print(fruit + " pie")
make_pie(4) # IndexError!
Rozwiązanie:
fruits = ["Apple", "Pear", "Orange"]
def make_pie(index):
try:
fruit = fruits[index]
except IndexError:
print(f"Nie mamy takiego składnika. Wybierz 0-{len(fruits)-1}")
else:
print(fruit + " pie")
make_pie(4) # Nie mamy takiego składnika. Wybierz 0-2
make_pie(1) # Pear pie
Przykład 7: Zapobiegnij błędom w postach
Problem:
facebook_posts = [
{'Likes': 21, 'Comments': 2},
{'Likes': 13, 'Comments': 2, 'Shares': 1},
{'Likes': 33, 'Comments': 8, 'Shares': 3},
{'Comments': 4, 'Shares': 2}, # Brak 'Likes'
{'Comments': 1, 'Shares': 1}, # Brak 'Likes'
{'Likes': 19, 'Comments': 3}
]
total_likes = 0
for post in facebook_posts:
total_likes = total_likes + post['Likes'] # KeyError!
Rozwiązanie:
facebook_posts = [
{'Likes': 21, 'Comments': 2},
{'Likes': 13, 'Comments': 2, 'Shares': 1},
{'Likes': 33, 'Comments': 8, 'Shares': 3},
{'Comments': 4, 'Shares': 2},
{'Comments': 1, 'Shares': 1},
{'Likes': 19, 'Comments': 3}
]
total_likes = 0
for post in facebook_posts:
try:
total_likes += post['Likes']
except KeyError:
# Post nie ma 'Likes', pomijamy
pass
print(f"Łączna liczba polubień: {total_likes}")
# Łączna liczba polubień: 86
Alternatywne rozwiązanie (bez try-except):
total_likes = 0
for post in facebook_posts:
total_likes += post.get('Likes', 0)
print(f"Łączna liczba polubień: {total_likes}")
Przykład 8: Program dzielący liczby
Wymagania:
- Pobierz dwie liczby
- Podziel pierwszą przez drugą
- Obsłuż: zły format, dzielenie przez 0, inne błędy
Rozwiązanie:
def dziel_liczby():
"""Program dzielący dwie liczby z pełną obsługą błędów."""
try:
# Pobranie liczb
a = float(input("Podaj pierwszą liczbę: "))
b = float(input("Podaj drugą liczbę: "))
# Dzielenie
wynik = a / b
except ValueError:
print("Błąd: Podano nieprawidłowy format liczby!")
except ZeroDivisionError:
print("Błąd: Nie można dzielić przez zero!")
except KeyboardInterrupt:
print("\nProgram przerwany przez użytkownika")
except Exception as e:
print(f"Nieoczekiwany błąd: {e}")
else:
print(f"Wynik dzielenia: {wynik:.2f}")
finally:
print("Koniec operacji")
# Uruchomienie
dziel_liczby()
Ulepszona wersja z pętlą:
def dziel_liczby_petla():
"""Wersja z ponawianiem przy błędach."""
while True:
try:
a = float(input("\nPodaj pierwszą liczbę (lub 'q' aby wyjść): "))
b = float(input("Podaj drugą liczbę: "))
if b == 0:
raise ZeroDivisionError("Dzielenie przez zero!")
wynik = a / b
print(f"Wynik: {a} / {b} = {wynik:.2f}")
break
except ValueError:
odpowiedz = input("Nieprawidłowy format! Spróbować ponownie? (t/n): ")
if odpowiedz.lower() != 't':
break
except ZeroDivisionError as e:
print(f"Błąd: {e}")
odpowiedz = input("Spróbować ponownie? (t/n): ")
if odpowiedz.lower() != 't':
break
dziel_liczby_petla()
Tworzenie własnych klas wyjątków
Możesz tworzyć własne typy wyjątków dziedzicząc po Exception.
class BledWalidacji(Exception):
"""Własny wyjątek dla błędów walidacji."""
pass
class UjemnaWartoscError(BledWalidacji):
"""Wyjątek dla ujemnych wartości."""
pass
def oblicz_pierwiastek(liczba):
"""Oblicza pierwiastek z walidacją."""
if liczba < 0:
raise UjemnaWartoscError("Nie można obliczyć pierwiastka z liczby ujemnej!")
return liczba ** 0.5
# Użycie
try:
wynik = oblicz_pierwiastek(-5)
except UjemnaWartoscError as e:
print(f"Błąd: {e}")
Assertion – assert
assert służy do sprawdzania założeń w kodzie podczas developmentu.
def podziel(a, b):
"""Dzieli a przez b."""
assert b != 0, "Dzielnik nie może być zerem!"
return a / b
# Użycie
wynik = podziel(10, 2) # OK
wynik = podziel(10, 0) # AssertionError: Dzielnik nie może być zerem!
Uwaga: assert jest wyłączany w trybie produkcyjnym (python -O). Do walidacji w produkcji używaj if + raise.
Dobre praktyki
- Łap konkretne błędy
- Nie ukrywaj błędów
- Obsługuj tylko to co potrafisz
- Używaj finally do sprzątania
- Informacyjne komunikaty błędów
Ćwiczenia – Obsługa błędów i wyjątków
Podstawy try-except
- Napisz program który próbuje otworzyć plik „dane.txt”. Obsłuż błąd gdy plik nie istnieje.
- Pobierz od użytkownika liczbę. Obsłuż błąd gdy wpisze tekst zamiast liczby.
- Stwórz listę 3 elementów. Spróbuj pobrać element o indeksie 5 i obsłuż błąd.
- Stwórz słownik z 3 kluczami. Spróbuj pobrać nieistniejący klucz i obsłuż błąd.
- Napisz program dzielący dwie liczby. Obsłuż dzielenie przez zero.
- Spróbuj dodać string do liczby i obsłuż błąd TypeError.
- Napisz program który próbuje skonwertować „abc” na int. Obsłuż błąd.
- Pobierz od użytkownika indeks listy. Obsłuż błąd gdy podadzielny typ lub poza zakresem.
- Otwórz plik do zapisu w katalogu bez uprawnień. Obsłuż PermissionError.
- Napisz program który łapie KeyboardInterrupt (Ctrl+C) i wyświetla komunikat.
Wiele except
- Napisz kalkulator obsługujący ValueError i ZeroDivisionError.
- Napisz funkcję otwierającą plik obsługującą FileNotFoundError i PermissionError.
- Pobierz od użytkownika wiek. Obsłuż ValueError i sprawdź czy nie jest ujemny (ValueError).
- Napisz program dostępu do słownika obsługujący KeyError i TypeError.
- Napisz funkcję konwertującą string na liczbę obsługującą ValueError i TypeError.
Przypisanie błędu do zmiennej
- Złap KeyError i wyświetl komunikat zawierający nazwę brakującego klucza.
- Złap ValueError i wyświetl dokładny komunikat błędu.
- Złap FileNotFoundError i wyświetl nazwę brakującego pliku.
- Złap wszystkie wyjątki jako zmienną i wyświetl ich typ.
- Złap IndexError i wyświetl komunikat z podanym indeksem.
Blok else
- Napisz program który próbuje otworzyć plik. W bloku else wyświetl jego zawartość.
- Pobierz liczbę od użytkownika. W else oblicz jej kwadrat.
- Otwórz plik do zapisu. W else zapisz dane. Obsłuż błędy.
- Pobierz dwie liczby i podziel. W else wyświetl wynik.
- Wczytaj dane ze słownika. W else przetwórz dane.
Blok finally
- Otwórz plik i zagwarantuj jego zamknięcie w finally.
- Napisz funkcję która zawsze wyświetla „Koniec” w finally.
- Zaimplementuj licznik prób w finally.
- Zapisz log operacji w finally (czy była udana czy nie).
- Zmierz czas operacji w finally.
raise – wywoływanie błędów
- Napisz funkcję sprawdzającą wiek. Wywołaj ValueError gdy wiek > 150.
- Napisz funkcję obliczającą pierwiastek. Wywołaj ValueError dla liczb ujemnych.
- Napisz funkcję dzielącą. Wywołaj ZeroDivisionError dla dzielnika = 0.
- Napisz funkcję walidującą email. Wywołaj ValueError gdy brak @ .
- Napisz funkcję sprawdzającą hasło (min 8 znaków). Wywołaj ValueError gdy za krótkie.
- Napisz funkcję która wywołuje TypeError gdy argument nie jest typu int.
- Napisz funkcję walidującą PESEL (11 cyfr). Wywołaj ValueError gdy niepoprawny.
- Napisz funkcję sprawdzającą czy liczba jest w zakresie 1-100. Wywołaj ValueError gdy nie.
- Napisz funkcję która wywołuje FileNotFoundError gdy podano pustą nazwę pliku.
- Napisz funkcję walidującą numer telefonu (9 cyfr). Wywołaj ValueError gdy błędny.
Walidacja danych użytkownika
- Napisz funkcję pobierającą dodatnią liczbę całkowitą. Powtarzaj dopóki nie będzie poprawna.
- Napisz funkcję pobierającą liczbę z zakresu 1-10. Waliduj i powtarzaj.
- Napisz funkcję pobierającą tak/nie. Akceptuj tylko te wartości.
- Napisz funkcję pobierającą datę w formacie DD-MM-YYYY. Waliduj format.
- Napisz funkcję pobierającą ocenę 1-6. Waliduj zakres.
Funkcje z obsługą błędów
- Napisz funkcję bezpiecznego dzielenia zwracającą None przy błędzie.
- Napisz funkcję bezpiecznego dostępu do listy zwracającą wartość domyślną.
- Napisz funkcję bezpiecznego dostępu do słownika z wartością domyślną.
- Napisz funkcję bezpiecznie konwertującą na int (zwraca 0 przy błędzie).
- Napisz funkcję bezpiecznie otwierającą plik (zwraca None przy błędzie).
Praca z plikami
- Napisz program który tworzy plik jeśli nie istnieje, otwiera jeśli istnieje.
- Napisz funkcję kopiującą plik z obsługą wszystkich błędów.
- Napisz program który próbuje wczytać JSON. Obsłuż błąd parsowania.
- Napisz funkcję dopisującą do logu z obsługą błędów.
- Napisz funkcję usuwającą plik z obsługą błędów.
Praca ze słownikami i listami
- Napisz funkcję bezpiecznie pobierającą wartość zagnieżdżoną ze słownika.
- Napisz funkcję aktualizującą słownik z obsługą błędów.
- Napisz funkcję usuwającą element z listy po wartości (obsłuż ValueError).
- Napisz funkcję sortującą listę mieszanych typów (obsłuż TypeError).
- Napisz funkcję łączącą dwa słowniki z obsługą błędów.
Konwersje i parsowanie
- Napisz funkcję konwertującą string na float z obsługą błędów.
- Napisz funkcję parsującą datę z różnych formatów.
- Napisz funkcję konwertującą string na bool (tak/nie, true/false, 1/0).
- Napisz funkcję parsującą listę liczb z stringa „1,2,3,4,5”.
- Napisz funkcję konwertującą temperaturę z obsługą błędnych jednostek.
Matematyka
- Napisz funkcję obliczającą silnię. Wywołaj ValueError dla n < 0.
- Napisz funkcję obliczającą pierwiastek z walidacją.
- Napisz funkcję obliczającą potęgę. Obsłuż OverflowError.
- Napisz funkcję obliczającą logarytm. Waliduj argument > 0.
- Napisz funkcję obliczającą procent. Waliduj zakres 0-100.
Kalkulator rozszerzony
- Napisz kalkulator z menu i pełną obsługą błędów.
- Dodaj historię operacji zapisywaną do pliku (obsłuż błędy).
- Dodaj tryb zaawansowany z funkcjami matematycznymi (obsłuż błędy dziedziny).
- Dodaj obsługę nawiasów w wyrażeniach.
- Dodaj możliwość zapisywania i wczytywania sesji.
Gry i aplikacje
- Napisz grę w zgadywanie liczby z pełną walidacją inputu.
- Napisz quiz z obsługą błędnych odpowiedzi.
- Napisz kółko i krzyżyk z walidacją ruchów.
- Napisz prostą grę tekstową z zapisem stanu (obsłuż błędy plików).
- Napisz symulator bankomatu z walidacją PIN i kwot.
Własne wyjątki
- Stwórz własny wyjątek
NiepoprawnyWiekError. - Stwórz własny wyjątek
BledWalidacjiEmail. - Stwórz hierarchię wyjątków dla aplikacji bankowej.
- Stwórz własny wyjątek
BledKonfiguracjiz dodatkowymi atrybutami. - Stwórz własny wyjątek
PrzekroczonoLimitz informacją o limicie.
Assert
- Użyj assert do sprawdzenia czy lista nie jest pusta przed operacją.
- Użyj assert do sprawdzenia typu argumentu funkcji.
- Użyj assert do sprawdzenia czy liczba jest w zakresie.
- Użyj assert do walidacji długości stringa.
- Użyj assert do sprawdzenia niezmiennika klasy.
Zadania kompleksowe
- Napisz system logowania użytkownika z pełną walidacją (login, hasło, próby).
- Napisz program zarządzający kontami bankowymi z walidacją operacji.
- Napisz parser plików konfiguracyjnych z obsługą wszystkich błędów.
- Napisz system rezerwacji z walidacją dat, dostępności, konfliktów.
- Napisz aplikację TODO z zapisem do pliku i pełną obsługą błędów.
- Napisz kalkulator kredytu z walidacją wszystkich parametrów.
- Napisz system ocen uczniów z walidacją ocen, obliczaniem średnich, zapisem.
- Napisz konwerter walut z obsługą błędów API, walidacją kwot.
- Napisz aplikację inwentaryzacji z walidacją stanów, cen, operacji.
- Napisz prosty interpreter poleceń z obsługą błędów składni i wykonania.
Debugging
- Napisz funkcję która loguje wszystkie wyjątki do pliku z datą, typem, traceback.
- Napisz dekorator który łapie i loguje wszystkie wyjątki funkcji.
- Napisz kontekst menedżer do obsługi zasobów z automatycznym sprzątaniem.
- Napisz funkcję która wyświetla czytelny komunikat błędu dla użytkownika końcowego.
- Napisz system retry (ponawiania operacji) z wykładniczym cofaniem.
Zaawansowane
- Napisz funkcję która łapie wiele typów wyjątków i reaguje inaczej na każdy.
- Napisz funkcję używającą re-raise do propagacji błędu z dodatkowym kontekstem.
- Napisz chain wyjątków (raise … from …).
- Napisz własny context manager używając try-finally.
- Napisz wrapper funkcji który zamienia wyjątki na kody błędów.