Czy jesteś programistą? Jeśli tak, to debugowanie stanowi fundamentalną umiejętność, niezależnie od języka programowania, którego używasz. W tym artykule poznasz, jak wykorzystać instrukcję `assert` w Pythonie do efektywnego debugowania swojego kodu.
Podczas tworzenia projektu, z pewnością zdefiniujesz liczne moduły, w tym funkcje, definicje klas i inne elementy. W procesie implementacji prawdopodobnie natrafisz na błędy lub nieoczekiwane rezultaty. Instrukcje `assert` są niezwykle przydatne w diagnozowaniu takich problemów.
W tym przewodniku nauczymy się składni i zastosowania instrukcji `assert`, analizując przykłady kodu w praktyce. Zrozumiemy, czym są błędy asercji i jak możemy je wykorzystać do identyfikacji i naprawy defektów w trakcie programowania.
Zacznijmy!
Wykorzystanie instrukcji `assert` w Pythonie
Zacznijmy od analizy składni instrukcji `assert`, a następnie przejdziemy do praktycznych przykładów.
Składnia instrukcji `assert`
Oto składnia instrukcji `assert` w Pythonie:
assert expression, message
Gdzie:
- `expression` jest dowolnym poprawnym wyrażeniem Pythona, które podlega ocenie. Może to być warunek dotyczący wartości zmiennej, wartości logicznej, rezultatu funkcji i innych.
- Dopóki `expression` jest prawdziwe (`True`), instrukcja `assert` nie wygeneruje błędu i nie zwróci żadnej wartości. Oznacza to, że program działa poprawnie.
- Gdy `expression` jest fałszywe (`False`), zgłaszany jest wyjątek `AssertionError`.
- `message` jest opcjonalnym tekstem, który może być wyświetlony w śledzeniu wstecznym, gdy zostanie zgłoszony wyjątek `AssertionError`.
Przejdźmy teraz do przykładów, które pokażą, jak `assert` może wspomóc pisanie czystego i wolnego od błędów kodu.
Przykłady kodu omawiane w tym artykule można znaleźć w tym GitHub Gist.
Praktyczne przykłady użycia instrukcji `assert` w Pythonie
Rozważmy następujący scenariusz. Załóżmy, że w kodzie masz zmienną `discount`, która reprezentuje rabat. Chcesz mieć pewność, że jej wartość nie przekracza `max_discount`.
Aby upewnić się, że nie ustawisz rabatu na zbyt wysoką wartość, możesz użyć asercji. Wyrażenie do sprawdzenia to: `discount <= max_discount`.
>>> max_discount = 50 >>> discount = 20 >>> assert discount <= max_discount
W tym przypadku `discount` (20) jest mniejszy niż `max_discount` (50), więc instrukcja `assert` nie wywołuje żadnego błędu.
Wyjątek `AssertionError`
Jeżeli wartość `discount` przekroczy `max_discount`, zostanie wygenerowany wyjątek `AssertionError`.
>>> discount = 75 >>> assert discount <= max_discount Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
Wiemy, że instrukcja `assert` pozwala nam także na dodanie opcjonalnej wiadomości tekstowej.
Użyjmy komunikatu z bardziej szczegółową informacją diagnostyczną. Do instrukcji `assert` dodajmy f-string w Pythonie, który zawiera wartości `discount` i `max_discount`.
>>> assert discount <= max_discount, f"discount powinien wynosić maksymalnie {max_discount}; otrzymano discount = {discount}" Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: discount powinien wynosić maksymalnie 50; otrzymano discount = 75
Jak widać, komunikat błędu `AssertionError` zawiera teraz wartości zmiennych `discount` i `max_discount`.
Debugowanie i testowanie funkcji Pythona z użyciem `assert`
Podczas definiowania funkcji, czasami nieświadomie można wprowadzić błędy (błędy logiczne), które uniemożliwiają jej prawidłowe działanie.
Rozważmy przykład. Załóżmy, że uczniowie mają możliwość odpowiedzieć na dodatkowe pytanie, za które otrzymują 10 punktów. 😄
Oto funkcja `get_final_score`:
- Przyjmuje ona aktualny wynik (`score`), zmienną logiczną `bonus` oraz opcjonalną liczbę punktów bonusowych.
- Jeżeli uczeń odpowiedział na dodatkowe pytanie (`bonus` jest `True`), do jego wyniku dodawane jest 10 punktów.
- Funkcja zwraca końcowy wynik.
def get_final_score(score,bonus): if bonus: score += 10 return score
Wywołajmy funkcję kilka razy. Dla wyników 34 i 40, z premią ustawioną na `True` i `False`, otrzymujemy wyniki 44 i 40.
print(get_final_score(34,True)) # 44 print(get_final_score(40,False)) # 40
Załóżmy, że maksymalna liczba punktów, jaką można uzyskać w teście, wynosi 50. Jeśli uczeń zdobędzie 49 punktów i odpowie na dodatkowe pytanie, funkcja `get_final_score` wyliczy wynik na 59.
print(get_final_score(49,True)) # 59
Technicznie, jest to możliwe. Jednak, załóżmy że uczeń nie może zdobyć więcej punktów niż maksymalna liczba punktów za test. 🙂
Zdefiniujmy zmienną `max_score`. Następnie, wynik zwrócony przez funkcję umieśćmy w zmiennej `final_score`.
Dodajmy asercję, która sprawdza, czy `final_score` jest mniejszy lub równy `max_score`.
def get_final_score(score,bonus): if bonus: score += 10 return score final_score = get_final_score(47,True) max_score = 50 assert final_score <= max_score
Teraz, dla wywołania funkcji `get_final_score(47,True)`, otrzymujemy wyjątek `AssertionError`:
Traceback (most recent call last): File "main.py", line 17, in <module> assert final_score <= max_score AssertionError
Dodajmy bardziej opisowy komunikat do instrukcji `assert`:
assert final_score <= max_score,f"final_score powinien wynosić maksymalnie {max_score}; otrzymano {final_score}"
Traceback (most recent call last): File "main.py", line 17, in <module> assert final_score <= max_score,f"final_score powinien wynosić maksymalnie {max_score}; otrzymano {final_score}" AssertionError: final_score powinien wynosić maksymalnie 50; otrzymano 57
Modyfikacja funkcji
Wróćmy i zmodyfikujmy funkcję `get_final_score`, aby naprawić nieoczekiwane działanie:
- Funkcja `get_final_score` przyjmuje teraz `max_score` jako parametr.
- Sprawdzamy, czy `bonus` jest prawdziwe. Jeśli tak, do wyniku dodajemy 10 punktów.
- Następnie sprawdzamy, czy wynik przekracza `max_score`. Jeśli tak, zwracamy `max_score`.
- W przeciwnym razie zwracamy wynik.
Teraz mamy pewność, że końcowy wynik jest zawsze mniejszy lub równy `max_score`.
def get_final_score(score,bonus,max_score): if bonus: score += 10 if score > max_score: return max_score return score
Jako szybkie ćwiczenie, spróbuj dodać kilka asercji, aby upewnić się, że funkcja działa poprawnie.
Ważna uwaga dotycząca wyjątku `AssertionError`
Pomimo że wyjątek `AssertionError` pojawia się, gdy wyrażenie ma wartość `False`, nie powinniśmy traktować go jako zwykłego wyjątku. Nie powinniśmy implementować takiego kodu:
try: <robię to> except AssertionError: <rób to>
W wcześniejszym przykładzie z funkcją `get_final_score`, użyliśmy asercji, aby sprawdzić, czy `final_score` jest mniejszy od `max_score`. Potem zmodyfikowaliśmy definicję funkcji, aby uniknąć występowania błędów asercji.
Do tego służą asercje. To testy poprawności kodu, które ułatwiają pisanie czystszego i bardziej niezawodnego kodu. Z drugiej strony, obsługa wyjątków służy do przewidywania i reagowania na nieoczekiwane błędy, które mogą wystąpić w trakcie działania programu. Często dotyczą one nieprawidłowych typów danych wejściowych i wartości.
Podsumowując, instrukcji `assert` w Pythonie należy używać do efektywnego debugowania, a nie do obsługi błędów `AssertionErrors` jako wyjątków.
Podsumowanie
Ten artykuł pomógł Ci zrozumieć, jak używać instrukcji `assert` w Pythonie. Oto podsumowanie kluczowych punktów:
- Asercje w Pythonie mają formę `assert expression`. Sprawdzają, czy wyrażenie jest prawdziwe. Jeżeli tak nie jest, zgłaszany jest wyjątek `AssertionError`.
- Można także użyć `assert expression, message`. W takim przypadku, komunikat zostanie wydrukowany, gdy wystąpi wyjątek `AssertionError`.
- Pamiętaj, aby nie używać mechanizmów obsługi wyjątków do zarządzania błędami asercji. Traktuj asercje jako narzędzie debugowania, które pomaga w walidacji poprawności kodu.
Asercje ułatwiają programistom proces debugowania. Aby mieć pewność, że wszystkie komponenty projektu działają poprawnie, warto nauczyć się pisać testy jednostkowe w Pythonie.
Na koniec, zapoznaj się z listą projektów w Pythonie dla początkujących, które mogą być Twoim następnym krokiem.
newsblog.pl