Lekce 4 - PyCharm - Debugging
V minulé lekci, PyCharm - Scopes, Live Templates, Databáze, Pluginy, jsme se zabývali scopes, Live Templates, databázemi a pluginy.
V dnešním Python tutoriálu si vysvětlíme, jak debugovat Python aplikace za pomocí IDE PyCharm. Vše si vyzkoušíme na jednoduchém příkladu.
Debugging
O debuggingu, tedy o procesu odstranění chyb v programu, se někdy hovoří také jako o jeho "ladění". Chyby v programu se většinou projevují tím, že je v nějaké proměnné nesprávná hodnota, která zapříčiní jeho nefunkčnost. Určitě jste se již dostali do situace, když váš program nefungoval správně.
Proč a kdy debugovat?
Možná jste prováděli zdlouhavé kontrolní výpisy různých proměnných, abyste zjistili, kde je chyba. Chybu lze ovšem odhalit mnohem snadněji, a to pomocí debugování. Program proto nejdříve spustíme ve speciálním debugovacím režimu, kde máme dovoleny určité "cheaty", jako např. program pozastavovat a nahlížet do obsahu proměnných.
Pozor, není ovšem pravda, že debugujeme jen když program nefunguje. Naopak, používáme jej co nejvíce to jde, a to i třeba pro kontrolu správnosti na kritických místech.
Příklad - Krokování cyklu
Mějme jednoduchý cyklus, ve kterém budeme vypisovat e-mailové adresy
spojením jména a jednotné koncovky např. @abc.cz
:
{PYTHON}
jmena = ['anna', 'pavel', 'lucie']
for jmeno in jmena:
mail = jmeno + '@abc.cz'
print(mail)
Jak si můžeme ověřit výše, program funguje korektně. Přesto si jej zkusíme oddebugovat, než se pustíme na nefunkční kód.
Breakpointy
Breakpoint je základní stavební kámen při debugování. Je to "bod" označující řádek, na kterém se program zastaví. Nám, jako programátorům, se v tu chvíli zobrazí kompletní kontext programu, tedy např. co je v tu chvíli kde uloženo. Protože program stojí, můžeme si vše snadno zkontrolovat.
Přidání breakpointu
Nyní se naučíme vkládat breakpointy a zastavovat na nich program. V
PyCharm se breakpoint na daný řádek vkládá kliknutím do prostoru
mezi číslem řádku a kódem (v editoru). Breakpoint pak poznáme
podle červeného kolečka a červeného řádku. Vložme tedy breakpoint na
řádek, kde se vypisují e-maily do konzole (print(mail)
).
Debug režim
Breakpoint máme přidaný. Když však program nyní spustíme, nic zvláštního se nestane. Aby se program opravdu zastavil, je potřeba ho spustit ve speciálním debugovacím režimu. K tomu slouží zelené tlačítko Debug main (hned vedle zeleného tlačítka "Play"), na které klikneme. Program se následně spustí a zastaví se, až narazí na náš breakpoint:
Záložka Debug
Otevřela se nová záložka Debug, která obsahuje velké množství informací:
Pojďme si popsat, co vidíme:
- Část výše na obrázku, ohraničená zeleně, obsahuje seznam všech aktuálně viditelných proměnných a jejich hodnoty.
- Žlutě ohraničená část obsahuje zásobník volání všech funkcí, které se zavolaly před breakpointem.
- Dále jsou na obrázku ještě červeně zvýrazněny dvě části (ovládání programu a breakpointů a krokování), které si popíšeme v následujících podkapitolách.
Ovládání programu a breakpointů
V první ohraničené červené části (svisle vlevo) se nachází tlačítka pro kontrolu ovládání programu a breakpointů:
- Rerun '(název_souboru)' Ctrl + F5 - Ukončí aktuální program a znovu ho spustí.
- Modify Run Configuration - Zobrazí nastavení pro debug.
- Resume Program F9 - Uvolní program z breakpointu a nechá program běžet a případně se zastaví o další breakpoint.
- Pause Program - Pozastaví vykonávání vybraného vlákna - funguje podobně jako breakpoint, pouze se nezobrazí žádné proměnné.
- Stop '(název_souboru)' Ctrl + F2 - Ukončí aktuální program.
- View Breakpoints Ctrl + Shift + F8 - Zobrazí seznam všech breakpointů.
- Mute Breakpoints - Potlačí všechny breakpointy. Když program narazí na breakpoint v debug módu, breakpoint bude ignorován.
Krokování
Ve druhé červeně ohraničené části (vodorovně) se nachází tlačítka pro krokování programu. Pomocí krokování můžeme nechat program pokročit na další řádek a zase zastavit:
- Step Over F8 (krok přes) - Provedeme další krok přes danou řádku s breakpointem, na které program aktuálně stojí. Pokud se na řádce volá funkce, necháme ji jen vykonat a pak přejdeme na další řádek.
- Step Into F7 (krok do) - Provedeme další krok "do" dané řádky. Dělá to samé co Step Over až na rozdíl, že pokud se na řádku volá funkce, přejdeme na první řádek ve funkci.
- Step Into My Code Alt + Shift + F7 (vynucený krok do) - Vynutí přechod do funkce na řádku i v případě, že se nejedná o naši metodu.
- Step Out Shift + F8 (krok ven) - Pomocí kroku ven vystoupíme z aktuálně prováděné funkce.
My se nacházíme v cyklu, kde pouze postupně vypisujeme jednu hodnotu.
Když se podíváme do výpisu konzole, zatím neuvidíme žádný výpis
(kromě možných hlášek od IDE). Stiskem tlačítka Step
Over (krok přes) se do konzole vypíše první hodnota (v našem
případě první e-mail) a my se v programu dostaneme na řádek s for
cyklem (for jmeno in jmena:
). Když tlačítko Step
Over stiskneme znovu, uvidíme v editoru kódu posun na další
položku seznamu, pro kterou se zase vykoná blok kódu (do konzole se tedy
vypíše druhý e-mail). Provedeme další krok přes danou řádku s
breakpointem, na které program aktuálně stojí. Pokud se na řádce volá
funkce, necháme ji jen vykonat a pak přejdeme na další řádek. Tímto
způsobem si můžeme odkrokovat celý cyklus:
Příklad - Debugování programu
Nakonec si dáme příklad opravdu k procvičení debugování. Máme např. tyto dva vnořené cykly, které by měly vypsat malou násobilku (0-9). Výstup by měl vypadat takto:
Konzolová aplikace
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
0 2 4 6 8 10 12 14 16 18
0 3 6 9 12 15 18 21 24 27
0 4 8 12 16 20 24 28 32 36
0 5 10 15 20 25 30 35 40 45
0 6 12 18 24 30 36 42 48 54
0 7 14 21 28 35 42 49 56 63
0 8 16 24 32 40 48 56 64 72
0 9 18 27 36 45 54 63 72 81
Poblém ale je, že výstup po spuštění programu vypadá takto:
{PYTHON}
n = 10
for i in range(n):
for j in range(n):
print(i * i, end=" ")
print()
Chybu budeme chtít najít a opravit za pomoci breakpointů a krokování. I když je možné vidět chybu na první pohled, pojďme si to společně odkrokovat. Ve složitějších aplikacích chyba takto snadno vidět nebude a proces debugování bude nutný.
Postup řešení příkladu
Breakpoint umístíme na řádek s vnějším for cyklem
(for i in range(n):
) a spustíme program v debug režimu.
Bude nás zajímat, jak se hodnoty inkrementují. Tlačítkem
Step Into (krok do) budeme postupně procházet přes oba cykly
a pozorovat proměnné i
a j
. Postupným krokováním
zjistíme, že vnitřní cyklus inkrementuje proměnné i
a
j
správně (sledujeme postupně v editoru kódu), ale výstupy v
konzoli odpovídají jiným hodnotám. Zaměříme se proto na
print()
, kde opravíme chybné i * i
na
i * j
a program již spustíme bez breakpointu. Výsledkem je
očekávaná malá násobilka čísel (0-9):
{PYTHON}
n = 10
for i in range(n):
for j in range(n):
print(i * j, end=" ")
print()
V příští lekci, PyCharm - Pokročilý debugging, si rozšíříme znalosti debugování a zaměříme se na nástroje usnadňující celý proces.