Výpisy chyb ze zanořených funkcí

Na začátku si ukážeme (nebo zopakujeme), jak Python vypíše chybu, která nastane v zanořené funkci.

Pročti si následující ukázkový příklad.

Tohle je absurdní ilustrační příklad, ne ukázka jak dobře programovat!

def podel(delenec, delitel):
    """Podělí čísla mezi sebou a vrátí výsledek."""
    return delenec / delitel        # řádek 3


def podel_nulou(cislo):
    """Vydělí dané číslo nulou a vrátí výsledek."""
    return podel(cislo, 0)          # řádek 8


def ukaz_priklad():
    """Spočítá ukázkový příklad a výsledek vypíše (nevrátí!)"""
    vysledek = podel_nulou(3)       # řádek 13
    print(vysledek)

ukaz_priklad()                      # řádek 16

Co se stane, ktyž tohle pustíš?

Traceback (most recent call last):
  File "ukazka.py", line 16, in <module>
    ukaz_priklad()
  File "ukazka.py", line 13, in ukaz_priklad
    vysledek = podel_nulou(3)
  File "ukazka.py", line 8, in podel_nulou
    return podel(cislo, 0)
  File "ukazka.py", line 3, in podel
    return delenec / delitel
ZeroDivisionError: division by zero

Všimni si, že každá z funkcí, jejíž volání vedlo k chybě, je uvedena ve výpisu. Skutečná chyba (tedy místo, které musíme opravit) je asi někde poblíž těchto míst:

  • Na řádku 3, ve funkci podel, vzniklo dělení nulou. Měla by funkce podel zjistit, jestli dostane nulu, a nějak na to zareagovat?
  • Na řádku 8, ve funkci podel_nulou, voláme podel s dělitelem 0. Má to tak opravdu být?
  • Na řádku 13, ve funkci ukaz_priklad, voláme funkci podel_nulou. Kdybychom to nedělali, chyba by taky nevznikla!
  • Na řádku 16, ne ve funkci, voláme funkci ukaz_priklad. Možná by to chtělo použít jiný příklad?

Ale Python (a asi ani ty) nemůže vědět, co tím programem programátor myslel, a kdy by tedy bylo nejlepší chybu opravit. Ukáže tedy v programu všechna místa, která k chybě vedla. Je na programátorovi, aby z nich vybral to nejvhodnější a zaměřil se na něj.

Tahle ukázka je samozřejmě jen teoretická, ale v reálných programech vypadá hlášení chyb stejně. Až takovou složitou hlášku uvidíš, nepanikař! Python se snaží co nejvíc napovědět a usnadnit ti chybu najít a opravit. Sice stroze a anglicky, ale snaží. Vyjdi mu vstříc a nauč tyhle se hlášky číst.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-pondeli:file:1",
      "title": "Chybové hlášky ze zanořených funkcí",
      "html": "\n          \n    \n\n    <h1>V&#xFD;pisy chyb ze zano&#x159;en&#xFD;ch funkc&#xED;</h1>\n<p>Na za&#x10D;&#xE1;tku si uk&#xE1;&#x17E;eme (nebo zopakujeme), jak Python vyp&#xED;&#x161;e chybu, kter&#xE1;\nnastane v&#xA0;zano&#x159;en&#xE9; funkci.</p>\n<p>Pro&#x10D;ti si n&#xE1;sleduj&#xED;c&#xED; uk&#xE1;zkov&#xFD; p&#x159;&#xED;klad.</p>\n<div class=\"admonition note\"><p>Tohle je absurdn&#xED; ilustra&#x10D;n&#xED; p&#x159;&#xED;klad, ne uk&#xE1;zka jak dob&#x159;e programovat!</p>\n</div><!-- XXX: automatic line numbers? -->\n\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">podel</span><span class=\"p\">(</span><span class=\"n\">delenec</span><span class=\"p\">,</span> <span class=\"n\">delitel</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Pod&#x11B;l&#xED; &#x10D;&#xED;sla mezi sebou a vr&#xE1;t&#xED; v&#xFD;sledek.&quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">delenec</span> <span class=\"o\">/</span> <span class=\"n\">delitel</span>        <span class=\"c1\"># &#x159;&#xE1;dek 3</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">podel_nulou</span><span class=\"p\">(</span><span class=\"n\">cislo</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Vyd&#x11B;l&#xED; dan&#xE9; &#x10D;&#xED;slo nulou a vr&#xE1;t&#xED; v&#xFD;sledek.&quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">podel</span><span class=\"p\">(</span><span class=\"n\">cislo</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>          <span class=\"c1\"># &#x159;&#xE1;dek 8</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">ukaz_priklad</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;Spo&#x10D;&#xED;t&#xE1; uk&#xE1;zkov&#xFD; p&#x159;&#xED;klad a v&#xFD;sledek vyp&#xED;&#x161;e (nevr&#xE1;t&#xED;!)&quot;&quot;&quot;</span>\n    <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">podel_nulou</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>       <span class=\"c1\"># &#x159;&#xE1;dek 13</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">vysledek</span><span class=\"p\">)</span>\n\n<span class=\"n\">ukaz_priklad</span><span class=\"p\">()</span>                      <span class=\"c1\"># &#x159;&#xE1;dek 16</span>\n</pre></div><p>Co se stane, kty&#x17E; tohle pust&#xED;&#x161;?</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gt\">Traceback (most recent call last):</span>\n  File <span class=\"nb\">&quot;ukazka.py&quot;</span>, line <span class=\"m\">16</span>, in <span class=\"n\">&lt;module&gt;</span>\n    <span class=\"n\">ukaz_priklad</span><span class=\"p\">()</span>\n  File <span class=\"nb\">&quot;ukazka.py&quot;</span>, line <span class=\"m\">13</span>, in <span class=\"n\">ukaz_priklad</span>\n    <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">podel_nulou</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n  File <span class=\"nb\">&quot;ukazka.py&quot;</span>, line <span class=\"m\">8</span>, in <span class=\"n\">podel_nulou</span>\n    <span class=\"k\">return</span> <span class=\"n\">podel</span><span class=\"p\">(</span><span class=\"n\">cislo</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n  File <span class=\"nb\">&quot;ukazka.py&quot;</span>, line <span class=\"m\">3</span>, in <span class=\"n\">podel</span>\n    <span class=\"k\">return</span> <span class=\"n\">delenec</span> <span class=\"o\">/</span> <span class=\"n\">delitel</span>\n<span class=\"gr\">ZeroDivisionError</span>: <span class=\"n\">division by zero</span>\n</pre></div><p>V&#x161;imni si, &#x17E;e ka&#x17E;d&#xE1; z&#xA0;funkc&#xED;, jej&#xED;&#x17E; vol&#xE1;n&#xED; vedlo k&#xA0;chyb&#x11B;, je uvedena ve v&#xFD;pisu.\nSkute&#x10D;n&#xE1; chyba (tedy m&#xED;sto, kter&#xE9; mus&#xED;me opravit) je asi n&#x11B;kde pobl&#xED;&#x17E; t&#x11B;chto\nm&#xED;st:</p>\n<ul>\n<li>Na &#x159;&#xE1;dku 3, ve funkci <code>podel</code>, vzniklo d&#x11B;len&#xED; nulou.\nM&#x11B;la by funkce <code>podel</code> zjistit, jestli dostane nulu, a n&#x11B;jak na to\nzareagovat?</li>\n<li>Na &#x159;&#xE1;dku 8, ve funkci <code>podel_nulou</code>, vol&#xE1;me <code>podel</code> s d&#x11B;litelem 0.\nM&#xE1; to tak opravdu b&#xFD;t?</li>\n<li>Na &#x159;&#xE1;dku 13, ve funkci <code>ukaz_priklad</code>, vol&#xE1;me funkci <code>podel_nulou</code>.\nKdybychom to ned&#x11B;lali, chyba by taky nevznikla!</li>\n<li>Na &#x159;&#xE1;dku 16, ne ve funkci, vol&#xE1;me funkci <code>ukaz_priklad</code>.\nMo&#x17E;n&#xE1; by to cht&#x11B;lo pou&#x17E;&#xED;t jin&#xFD; p&#x159;&#xED;klad?</li>\n</ul>\n<p>Ale Python (a asi ani ty) nem&#x16F;&#x17E;e v&#x11B;d&#x11B;t, co t&#xED;m programem program&#xE1;tor myslel,\na kdy by tedy bylo nejlep&#x161;&#xED; chybu opravit.\nUk&#xE1;&#x17E;e tedy v&#xA0;programu v&#x161;echna m&#xED;sta, kter&#xE1; k chyb&#x11B; vedla.\nJe na program&#xE1;torovi, aby z nich vybral to nejvhodn&#x11B;j&#x161;&#xED; a zam&#x11B;&#x159;il se na n&#x11B;j.</p>\n<p>Tahle uk&#xE1;zka je samoz&#x159;ejm&#x11B; jen teoretick&#xE1;, ale v&#xA0;re&#xE1;ln&#xFD;ch programech vypad&#xE1;\nhl&#xE1;&#x161;en&#xED; chyb stejn&#x11B;.\nA&#x17E; takovou slo&#x17E;itou hl&#xE1;&#x161;ku uvid&#xED;&#x161;, nepanika&#x159;!\nPython se sna&#x17E;&#xED; co nejv&#xED;c napov&#x11B;d&#x11B;t a usnadnit ti chybu naj&#xED;t a opravit.\nSice stroze a anglicky, ale sna&#x17E;&#xED;.\nVyjdi mu vst&#x159;&#xED;c a nau&#x10D; tyhle se hl&#xE1;&#x161;ky &#x10D;&#xED;st.</p>\n\n\n        "
    }
  }
}