Programy dostają czasem dane, których autor się nie spodziewał: tekst zamiast liczby, zero w mianowniku, brakujący element. Zamiast kończyć się komunikatem o błędzie, dobrze napisany program potrafi na to zareagować. Na lekcji uczniowie obsługują trzy rodzaje takich sytuacji instrukcją try ... except.
Scenariusz jest przeznaczony na 45 minut dla klasy znającej funkcje i konwersję typów — na przykład po lekcjach o funkcjach i typach danych.
Przygotowanie stanowisk
Potrzebny jest Python 3 i edytor lub IDLE. Rozpakuj pakiet z sekcji materiałów do osobnego folderu i uruchamiaj skrypty z tego folderu. Program uruchomisz przez Run → Run Module albo poleceniem python start.py, python3 start.py lub py start.py.
Cele i plan lekcji
Po zajęciach uczeń potrafi:
- przeczytać komunikat błędu i nazwać typ wyjątku (
ValueError,ZeroDivisionError,IndexError); - obsłużyć wyjątek blokiem
try ... excepti zwrócić wartość zastępczą; - zgłosić własny błąd instrukcją
raisei użyćfinally; - wyjaśnić, że przechwytywać należy konkretne wyjątki, a nie wszystkie.
| Czas | Praca na lekcji |
|---|---|
| 0–5 min | Problem: program zatrzymuje się na int("abc") |
| 5–15 min | try i except, nazwa wyjątku |
| 15–22 min | raise, finally, wartość zastępcza |
| 22–37 min | Trzy zadania samodzielne |
| 37–42 min | Omówienie wyników |
| 42–45 min | Pytania kontrolne |
try, except, raise, finally
Blok try zawiera kod, który może zgłosić błąd. Jeśli się to stanie, wykonanie przechodzi do pasującego bloku except, a program działa dalej. Najlepiej podawać konkretny typ wyjątku, np. except ValueError, bo „goły” except ukrywa także błędy programisty (literówki w nazwach).
Najczęstsze wyjątki w lekcji: ValueError (np. int("abc")), ZeroDivisionError (dzielenie przez zero), IndexError (indeks poza listą), TypeError (zły typ danych). Własny błąd zgłaszamy instrukcją raise ValueError("opis"), a opis odczytamy przez except ValueError as blad. Blok finally wykonuje się zawsze, niezależnie od tego, czy błąd wystąpił — używa się go do porządków, np. zamknięcia pliku.
Zadania
Zadanie 1. Bezpieczna liczba. Napisz funkcję wczytaj_liczbe(tekst), która zwraca liczbę całkowitą albo None, gdy tekst nie jest liczbą. Sprawdź "12", "-7", "abc", "3.5" i pusty napis.
Zadanie 2. Dzielenie. Napisz funkcję podziel(a, b), która zamiast zgłaszać błąd dla b = 0 zwraca napis "dzielenie przez zero". Sprawdź podziel(10, 4) i podziel(5, 0).
Zadanie 3. Średnia z tekstów. Napisz funkcję srednia_z_tekstow(lista), która pomija niepoprawne elementy, zlicza je i zwraca średnią z dwoma miejscami oraz liczbę błędów. Gdy nie ma poprawnych liczb, ma zgłosić ValueError. Sprawdź listy ["8", "x", "10", "4"] i ["a", "b"] (z blokiem finally).
Dla chętnych: napisz funkcję zwracającą element listy o podanym indeksie albo None, gdy indeks jest poza zakresem.
Rozwiązanie i wyniki
def wczytaj_liczbe(tekst):
try:
return int(tekst)
except ValueError:
return None
def podziel(a, b):
try:
return a / b
except ZeroDivisionError:
return "dzielenie przez zero"
def srednia_z_tekstow(lista):
liczby = []
bledy = 0
for t in lista:
n = wczytaj_liczbe(t)
if n is None:
bledy = bledy + 1
else:
liczby.append(n)
if len(liczby) == 0:
raise ValueError("brak poprawnych liczb")
return round(sum(liczby) / len(liczby), 2), bledy
# Zadanie 1
for t in ["12", "-7", "abc", "3.5", ""]:
print(repr(t), wczytaj_liczbe(t))
# Zadanie 2
print(podziel(10, 4), podziel(5, 0))
# Zadanie 3
print(srednia_z_tekstow(["8", "x", "10", "4"]))
try:
srednia_z_tekstow(["a", "b"])
except ValueError as blad:
print("Blad:", blad)
finally:
print("Koniec obliczen")
Program wypisze:
'12' 12
'-7' -7
'abc' None
'3.5' None
'' None
2.5 dzielenie przez zero
(7.33, 1)
Blad: brak poprawnych liczb
Koniec obliczen
Zauważ, że "3.5" i pusty napis dają None — int nie czyta ułamków zapisanych tekstem. Średnia z 8, 10 i 4 to 22/3, czyli 7.33, a jeden element ("x") został pominięty. Zadanie dla chętnych (rozszerzenie.py) wypisuje:
2 None
Typowe błędy
| Objaw | Co sprawdzić |
|---|---|
| Program nadal kończy się błędem | Blok except ma inny typ wyjątku niż zgłoszony. |
| Błąd literówki „znika” | Użyto gołego except:, który przechwytuje wszystko, także własne pomyłki. |
Funkcja zwraca None, a oczekiwano liczby | Wartość zastępcza została zwrócona, ale wynik użyto bez sprawdzenia is None. |
int("3.5") daje None | To ValueError; przekonwertuj przez float, jeśli ułamki są dopuszczalne. |
Komunikat z raise nie pojawia się | Brak as blad albo nie wypisano zmiennej. |
finally wypisuje się też bez błędu | To zamierzone zachowanie — finally wykonuje się zawsze. |
Pytania kontrolne i punktacja
- Który wyjątek zgłosi
10 / 0? - Kiedy wykona się blok
finally? - Dlaczego lepiej pisać
except ValueErrorniż samoexcept?
Odpowiedzi: ZeroDivisionError. Zawsze — po poprawnym wykonaniu bloku try i po obsłużonym lub nieobsłużonym błędzie. Bo konkretny wyjątek nie ukrywa innych, nieoczekiwanych błędów.
Proponowana punktacja (razem 10 punktów): zadanie 1 — try/except 2 pkt, pięć wyników 1 pkt; zadanie 2 — obsługa zera 2 pkt, dwa wyniki 1 pkt; zadanie 3 — pomijanie błędów i licznik 2 pkt, raise 1 pkt, finally i test 1 pkt. Zadanie dla chętnych nie jest wymagane do pełnej oceny.
Materiały do pobrania
Rozpakuj ZIP przed otwarciem plików. Materiały są dostępne bez logowania; publiczne rozwiązanie służy nauce i samodzielnemu sprawdzeniu, a nie poufnemu sprawdzianowi.
Co dalej?
Następny krok to testowanie funkcji instrukcją assert i praca z plikami, w których błędy zdarzają się najczęściej. Ten materiał rozwija dział o obsłudze błędów w kursie Python w TablicaPro, gdzie znajdziesz prezentacje, ćwiczenia i testy do prowadzenia lekcji.
Źródła techniczne: błędy i wyjątki w oficjalnym tutorialu. Zobacz też lekcję o plikach tekstowych.
Poprowadź kolejne lekcje Python
Pełny kurs: prezentacje, ćwiczenia i testy do pracy z klasą.
Kup dostęp do kursu Python →