15. Python – obsługa błędów i wyjątków


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ść:

  1. try – zawsze jako pierwsze
  2. except – jeden lub więcej
  3. else – opcjonalnie, tylko jeśli nie było błędu
  4. finally – 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

  1. Napisz program który próbuje otworzyć plik „dane.txt”. Obsłuż błąd gdy plik nie istnieje.
  2. Pobierz od użytkownika liczbę. Obsłuż błąd gdy wpisze tekst zamiast liczby.
  3. Stwórz listę 3 elementów. Spróbuj pobrać element o indeksie 5 i obsłuż błąd.
  4. Stwórz słownik z 3 kluczami. Spróbuj pobrać nieistniejący klucz i obsłuż błąd.
  5. Napisz program dzielący dwie liczby. Obsłuż dzielenie przez zero.
  6. Spróbuj dodać string do liczby i obsłuż błąd TypeError.
  7. Napisz program który próbuje skonwertować „abc” na int. Obsłuż błąd.
  8. Pobierz od użytkownika indeks listy. Obsłuż błąd gdy podadzielny typ lub poza zakresem.
  9. Otwórz plik do zapisu w katalogu bez uprawnień. Obsłuż PermissionError.
  10. Napisz program który łapie KeyboardInterrupt (Ctrl+C) i wyświetla komunikat.

Wiele except

  1. Napisz kalkulator obsługujący ValueError i ZeroDivisionError.
  2. Napisz funkcję otwierającą plik obsługującą FileNotFoundError i PermissionError.
  3. Pobierz od użytkownika wiek. Obsłuż ValueError i sprawdź czy nie jest ujemny (ValueError).
  4. Napisz program dostępu do słownika obsługujący KeyError i TypeError.
  5. Napisz funkcję konwertującą string na liczbę obsługującą ValueError i TypeError.

Przypisanie błędu do zmiennej

  1. Złap KeyError i wyświetl komunikat zawierający nazwę brakującego klucza.
  2. Złap ValueError i wyświetl dokładny komunikat błędu.
  3. Złap FileNotFoundError i wyświetl nazwę brakującego pliku.
  4. Złap wszystkie wyjątki jako zmienną i wyświetl ich typ.
  5. Złap IndexError i wyświetl komunikat z podanym indeksem.

Blok else

  1. Napisz program który próbuje otworzyć plik. W bloku else wyświetl jego zawartość.
  2. Pobierz liczbę od użytkownika. W else oblicz jej kwadrat.
  3. Otwórz plik do zapisu. W else zapisz dane. Obsłuż błędy.
  4. Pobierz dwie liczby i podziel. W else wyświetl wynik.
  5. Wczytaj dane ze słownika. W else przetwórz dane.

Blok finally

  1. Otwórz plik i zagwarantuj jego zamknięcie w finally.
  2. Napisz funkcję która zawsze wyświetla „Koniec” w finally.
  3. Zaimplementuj licznik prób w finally.
  4. Zapisz log operacji w finally (czy była udana czy nie).
  5. Zmierz czas operacji w finally.

raise – wywoływanie błędów

  1. Napisz funkcję sprawdzającą wiek. Wywołaj ValueError gdy wiek > 150.
  2. Napisz funkcję obliczającą pierwiastek. Wywołaj ValueError dla liczb ujemnych.
  3. Napisz funkcję dzielącą. Wywołaj ZeroDivisionError dla dzielnika = 0.
  4. Napisz funkcję walidującą email. Wywołaj ValueError gdy brak @ .
  5. Napisz funkcję sprawdzającą hasło (min 8 znaków). Wywołaj ValueError gdy za krótkie.
  6. Napisz funkcję która wywołuje TypeError gdy argument nie jest typu int.
  7. Napisz funkcję walidującą PESEL (11 cyfr). Wywołaj ValueError gdy niepoprawny.
  8. Napisz funkcję sprawdzającą czy liczba jest w zakresie 1-100. Wywołaj ValueError gdy nie.
  9. Napisz funkcję która wywołuje FileNotFoundError gdy podano pustą nazwę pliku.
  10. Napisz funkcję walidującą numer telefonu (9 cyfr). Wywołaj ValueError gdy błędny.

Walidacja danych użytkownika

  1. Napisz funkcję pobierającą dodatnią liczbę całkowitą. Powtarzaj dopóki nie będzie poprawna.
  2. Napisz funkcję pobierającą liczbę z zakresu 1-10. Waliduj i powtarzaj.
  3. Napisz funkcję pobierającą tak/nie. Akceptuj tylko te wartości.
  4. Napisz funkcję pobierającą datę w formacie DD-MM-YYYY. Waliduj format.
  5. Napisz funkcję pobierającą ocenę 1-6. Waliduj zakres.

Funkcje z obsługą błędów

  1. Napisz funkcję bezpiecznego dzielenia zwracającą None przy błędzie.
  2. Napisz funkcję bezpiecznego dostępu do listy zwracającą wartość domyślną.
  3. Napisz funkcję bezpiecznego dostępu do słownika z wartością domyślną.
  4. Napisz funkcję bezpiecznie konwertującą na int (zwraca 0 przy błędzie).
  5. Napisz funkcję bezpiecznie otwierającą plik (zwraca None przy błędzie).

Praca z plikami

  1. Napisz program który tworzy plik jeśli nie istnieje, otwiera jeśli istnieje.
  2. Napisz funkcję kopiującą plik z obsługą wszystkich błędów.
  3. Napisz program który próbuje wczytać JSON. Obsłuż błąd parsowania.
  4. Napisz funkcję dopisującą do logu z obsługą błędów.
  5. Napisz funkcję usuwającą plik z obsługą błędów.

Praca ze słownikami i listami

  1. Napisz funkcję bezpiecznie pobierającą wartość zagnieżdżoną ze słownika.
  2. Napisz funkcję aktualizującą słownik z obsługą błędów.
  3. Napisz funkcję usuwającą element z listy po wartości (obsłuż ValueError).
  4. Napisz funkcję sortującą listę mieszanych typów (obsłuż TypeError).
  5. Napisz funkcję łączącą dwa słowniki z obsługą błędów.

Konwersje i parsowanie

  1. Napisz funkcję konwertującą string na float z obsługą błędów.
  2. Napisz funkcję parsującą datę z różnych formatów.
  3. Napisz funkcję konwertującą string na bool (tak/nie, true/false, 1/0).
  4. Napisz funkcję parsującą listę liczb z stringa „1,2,3,4,5”.
  5. Napisz funkcję konwertującą temperaturę z obsługą błędnych jednostek.

Matematyka

  1. Napisz funkcję obliczającą silnię. Wywołaj ValueError dla n < 0.
  2. Napisz funkcję obliczającą pierwiastek z walidacją.
  3. Napisz funkcję obliczającą potęgę. Obsłuż OverflowError.
  4. Napisz funkcję obliczającą logarytm. Waliduj argument > 0.
  5. Napisz funkcję obliczającą procent. Waliduj zakres 0-100.

Kalkulator rozszerzony

  1. Napisz kalkulator z menu i pełną obsługą błędów.
  2. Dodaj historię operacji zapisywaną do pliku (obsłuż błędy).
  3. Dodaj tryb zaawansowany z funkcjami matematycznymi (obsłuż błędy dziedziny).
  4. Dodaj obsługę nawiasów w wyrażeniach.
  5. Dodaj możliwość zapisywania i wczytywania sesji.

Gry i aplikacje

  1. Napisz grę w zgadywanie liczby z pełną walidacją inputu.
  2. Napisz quiz z obsługą błędnych odpowiedzi.
  3. Napisz kółko i krzyżyk z walidacją ruchów.
  4. Napisz prostą grę tekstową z zapisem stanu (obsłuż błędy plików).
  5. Napisz symulator bankomatu z walidacją PIN i kwot.

Własne wyjątki

  1. Stwórz własny wyjątek NiepoprawnyWiekError.
  2. Stwórz własny wyjątek BledWalidacjiEmail.
  3. Stwórz hierarchię wyjątków dla aplikacji bankowej.
  4. Stwórz własny wyjątek BledKonfiguracji z dodatkowymi atrybutami.
  5. Stwórz własny wyjątek PrzekroczonoLimit z informacją o limicie.

Assert

  1. Użyj assert do sprawdzenia czy lista nie jest pusta przed operacją.
  2. Użyj assert do sprawdzenia typu argumentu funkcji.
  3. Użyj assert do sprawdzenia czy liczba jest w zakresie.
  4. Użyj assert do walidacji długości stringa.
  5. Użyj assert do sprawdzenia niezmiennika klasy.

Zadania kompleksowe

  1. Napisz system logowania użytkownika z pełną walidacją (login, hasło, próby).
  2. Napisz program zarządzający kontami bankowymi z walidacją operacji.
  3. Napisz parser plików konfiguracyjnych z obsługą wszystkich błędów.
  4. Napisz system rezerwacji z walidacją dat, dostępności, konfliktów.
  5. Napisz aplikację TODO z zapisem do pliku i pełną obsługą błędów.
  6. Napisz kalkulator kredytu z walidacją wszystkich parametrów.
  7. Napisz system ocen uczniów z walidacją ocen, obliczaniem średnich, zapisem.
  8. Napisz konwerter walut z obsługą błędów API, walidacją kwot.
  9. Napisz aplikację inwentaryzacji z walidacją stanów, cen, operacji.
  10. Napisz prosty interpreter poleceń z obsługą błędów składni i wykonania.

Debugging

  1. Napisz funkcję która loguje wszystkie wyjątki do pliku z datą, typem, traceback.
  2. Napisz dekorator który łapie i loguje wszystkie wyjątki funkcji.
  3. Napisz kontekst menedżer do obsługi zasobów z automatycznym sprzątaniem.
  4. Napisz funkcję która wyświetla czytelny komunikat błędu dla użytkownika końcowego.
  5. Napisz system retry (ponawiania operacji) z wykładniczym cofaniem.

Zaawansowane

  1. Napisz funkcję która łapie wiele typów wyjątków i reaguje inaczej na każdy.
  2. Napisz funkcję używającą re-raise do propagacji błędu z dodatkowym kontekstem.
  3. Napisz chain wyjątków (raise … from …).
  4. Napisz własny context manager używając try-finally.
  5. Napisz wrapper funkcji który zamienia wyjątki na kody błędów.