Debugowanie za pomocą print()

Na początek zastosujmy najprostszą formę debugowania stosowaną przez najstarszych Indian😂

Printowanie, czyli wypisywanie stanu

Wypisywanie na konsolę wiadomości można nazwać pierwszą strategią mającą na celu poznanie stanu programu w danym momencie. Możemy to nazwać taką bardzo prymitywną (i wciąż bardzo szeroko stosowaną) formą debugowania.

W Pythonie użyjemy funkcji print(), która wypisze nam dowolny tekst na konsolę uruchomieniową. Przykładem użycia print() może być opis poszczególnych bloków programu. Usprawnijmy nasz kod o takie opisy:

# Cats inventory advanced manager
print("Starting program")

print("Preparing data")
cat1 = "Kitty"
cat2 = "Pussy"
cat3 = "Paw"

print("Initialising cats list")
cats = []

print("Adding cats to list")
cats.append(cat1)
cats.append(cat2)
cats.append(cat3)

print("Returning list")
print(cats)

Uruchamiamy ponownie program i tym razem widzimy taki oto wynik:

C:\Projects\cattify\venv\Scripts\python.exe C:/Projects/cattify/cats_main.py
Starting program
Preparing data
Initialising cats list
Adding cats to list
Returning list
['Kitty', 'Pussy', 'Paw']

Process finished with exit code 0

Ok. Już wiemy więcej o wykonaniu programu i jego poszczególnych blokach… niby nie daje nam to zbytniej pomocy. Czy na pewno? Wykonajmy proste ćwiczenie.

Psujemy program

Celowo wprowadźmy błąd w postaci odniesienia do nieistniejącego kota. Zrobimy to dla linii:

cats.append(cat2)

Zmień ją na:

cats.append(cat233)

Następnie uruchom program. Powinieneś otrzymać taki wynik:

C:\Projects\cattify\venv\Scripts\python.exe C:/Projects/cattify/cats_main.py
Traceback (most recent call last):
  File "C:/Projects/cattify/cats_main.py", line 14, in <module>
    cats.append(cat233)
NameError: name 'cat233' is not defined
Starting program
Preparing data
Initialising cats list
Adding cats to list

Process finished with exit code 1

No jest błąd (w PyCharm powinieneś zobaczyć sporo czerwonego tekstu)… Zaczynając od końca. Zauważ, że na końcu ostatniej linii mamy exit code 1, co zdecydowanie oznacza niepoprawne zakończenie programu🤕

Następnie idąc w górę trafiamy na linię:

Adding cats to list

Hmm przejdźmy do kodu gdzie wpisujemy Adding cats to list. Kolejne kroki w naszym programie, które printujemy:

print("Returning list")
print(cats)

nie zostały wykonane. Czyli problem leży gdzieś pomiędzy ostatnim wyprowadzonym na konsolę printem a wiadomością, która nie została wypisana.

Miejsce problemu wydedukowane na podstawie printów:
uruchamianie programu python

AHA! Już mogę podejrzewać gdzie jest błąd!

Dzięki naszym printom wiem do jakiego momentu wykonał się nasz program. I mniej więcej potrafimy określić jaka część programu działa poprawnie.

Oczywiście informacja o błędzie na naszej konsoli:

Traceback (most recent call last):
  File "C:/Projects/cattify/cats_main.py", line 14, in <module>
    cats.append(cat233)
NameError: name 'cat233' is not defined

Mówi nam dokładnie, że błąd jest w line 14 oraz jaka jest prawdopodobna przyczyna problemów. Jednak to nie dyskwalifikuje naszych printów.

Za pomocą printów posiadamy informacje dodatkowe o tym co zostało zrealizowane i łatwiej nam się jest odnaleźć w obszarze gdzie wystąpił błąd.

Wypisujemy wartości

Kolejnym krokiem może być wypisanie wartości. W naszym przypadku mamy problem z listą. Dodajmy więc dodatkowe informacje w formie kodu:

print(f'cats list contains: {cats}')

W ten sposób wypiszemy zawartość listy, poprzedzonej opisem do jakiej zmiennej należy zawartość.

Zrobimy taki print dla każdej modyfikacji listy. Czyli w kodzie może to wyglądać tak:

# Cats inventory advanced manager
print("Starting program")

print("Preparing data")
cat1 = "Kitty"
cat2 = "Pussy"
cat3 = "Paw"

print("Initialising cats list")
cats = []
print(f'cats list contains: {cats}')

print("Adding cats to list")
cats.append(cat1)
print(f'cats list contains: {cats}')
cats.append(cat233)
print(f'cats list contains: {cats}')
cats.append(cat3)
print(f'cats list contains: {cats}')

print("Returning list")
print(cats)

Uruchomimy teraz nasz program. Wynik to:

C:\Projects\cattify\venv\Scripts\python.exe C:/Projects/cattify/cats_main.py
Traceback (most recent call last):
  File "C:/Projects/cattify/cats_main.py", line 16, in <module>
    cats.append(cat233)
NameError: name 'cat233' is not defined
Starting program
Preparing data
Initialising cats list
cats list contains: []
Adding cats to list
cats list contains: ['Kitty']

Process finished with exit code 1

Tutaj już bez problemu możemy przeczytać, że główny problem nastąpił gdzieś po dodaniu pierwszego kota 'Kitty' do listy. Możemy też przypuszczać, że przyczyna problemu tkwi w linii w, której do listy dodajemy zmienną z kolejnym kotem😾 Tym samym jeszcze bardziej zawęziliśmy obszar problemów.

TIP: Obecna strategia debugowania jest bardziej formą logowania czyli wypisywania niezbędnych informacji podczas wykonywania programu.

Logowanie to osobny, niezwykle ważny temat. Z dobrych logów możemy rozszyfrować przyczynę błędu i zaawansowane debugowanie będzie wtedy znacznie efektywniejsze a czasami nawet niepotrzebne.

Naprawiamy i podziwiamy

Pozostało nam teraz tylko poprawić zepsutą linię:

cats.append(cat233)

Na poprawną:

cats.append(cat2)

I uruchomić program, dzięki czemu zobaczymy dość dokładny opis kroków programu i wartości listy:

Starting program
Preparing data
Initialising cats list
cats list contains: []
Adding cats to list
cats list contains: ['Kitty']
cats list contains: ['Kitty', 'Pussy']
cats list contains: ['Kitty', 'Pussy', 'Paw']
Returning list
['Kitty', 'Pussy', 'Paw']

No dobra, tak sobie prymitywnie podebugowaliśmy ale chyba nie będziemy wszędzie tych printów wrzucać? Na dłuższą metę byłoby to męczące. Wyobraź sobie, że będziemy mieć bardzo dużo różnych zmiennych – byłby niezły chaos z setkami printów w kodzie..

Dlatego poznamy bardziej zaawansowaną strategię debugowania a pomoże nam w niej potężne narzędzie, które otrzymujemy razem z PyCharmem.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *