Výjimky

Pojďme si prohloubit znalosti o chybách, neboli odborně o výjimkách (angl. exceptions).

Vezměme následující funkci:

def nacti_cislo():
    odpoved = input('Zadej číslo: ')
    return int(odpoved)

Když uživatel nezadá číslice, ale třeba text cokolada, nastene výjimka jménem ValueError (chyba hodnoty) a Python vypíše odpovídající chybovou hlášku.

Traceback (most recent call last):
  File "ukazka.py", line 3, in nacti_cislo
    cislo = int(odpoved)
ValueError: invalid literal for int() with base 10: 'cokolada'

Program volá funkci int() pro neco, co nedává smysl jako číslo. Co s tím má chudák funkce int dělat? Není žádná rozumná hodnota, kterou by mohla vrátit. Převádění tohoto textu na celé číslo nedává smysl.

Až funkce nacti_cislo nejlíp „ví“, co se má stát, když uživatel nezadá číslice. Stačí se uživatele zeptat znovu! Kdybychom měli funkci, která zjistí jestli jsou v řetězci jen číslice, mohlo by to fungovat nějak takhle:

def nacti_cislo():
    while True:
        odpoved = input('Zadej číslo: ')
        if obsahuje_jen_cislice(odpoved):
            return int(odpoved)  # máme výsledek, funkce končí
        else:
            print('To nebylo číslo!')
            # ... a zeptáme se znovu -- cyklus `while` pokračuje

Kde ale vzít funkci obsahuje_jen_cislice? Nechceme ji psát znovu – funkce int sama nejlíp pozná, co se dá převést na číslo a co ne. A dokonce nám to dá vědět – chybou, kterou můžeme zachytit.

Ošetření chyby

Pro zachycení chyby má Python příkaz try/except.

def nacti_cislo():
    while True:
        odpoved = input('Zadej číslo: ')
        try:
            return int(odpoved)
        except ValueError:
            print('To nebylo číslo!')

Jak to funguje? Příkazy v bloku uvozeném příkazem try se normálně provádějí, ale když nastane uvedená výjimka, Python přeskočí zbytek bloky try a provede všechno v bloku except. Pokud výjimka nenastala, přeskočí se celý blok except.

Druhy chyb

A co je to ValueError? To je typ chyby. Podobných typů je spousta. Všechny jsou popsané v dokumentaci; pro nás jsou (nebo budou) důležité tyto:

BaseException
 ├── SystemExit                     vyvolána funkcí exit()
 ├── KeyboardInterrupt              vyvolána po stisknutí Ctrl+C
 ╰── Exception
      ├── ArithmeticError
      │    ╰── ZeroDivisionError    dělení nulou
      ├── AssertionError            nepovedený příkaz `assert`
      ├── AttributeError            neexistující atribut/metoda, např. 'abc'.len
      ├── ImportError               nepovedený import
      ├── LookupError
      │    ╰── IndexError           neexistující index, např. 'abc'[999]
      ├── NameError                 použití neexistujícího jména proměnné
      │    ╰── UnboundLocalError    použití proměnné, která ještě nebyla nastavená
      ├── SyntaxError               špatná syntaxe, program je nečitelný/nepoužitelný
      │    ╰── IndentationError     špatné odsazení
      │         ╰── TabError        kombinování mezer a tabulátorů v odsazení
      ├── TypeError                 špatný typ, např. len(9)
      ╰── ValueError                špatná hodnota, např. int('xyz')

Když odchytáváš obecnou výjimku, chytnou se i všechny podřízené typy výjimek – například except ArithmeticError: zachytí i ZeroDivisionError. A except Exception: zachytí všechny výjimky, které běžně chceš zachytit.

Nechytej je všechny!

Většinu chyb není potřeba ošetřovat.

Nastane-li nečekaná situace, je téměř vždy mnohem lepší program ukončit, než se snažit pokračovat dál počítat se špatnými hodnotami. Navíc chybový výstup, který Python standardně připraví, může hodně ulehčit hledání chyby.

Zachytávej tedy jenom ty chyby, které očekáváš – víš přesně, která chyba může nastat a proč, a máš možnost správně zareagovat.

V našem příkladu to platí pro ValueError z funkce int.

Co ale dělat, kdyš uživatel chce ukončit program a zmáčkne Ctrl+C? Nebo když se mu porouchá klávesnice a selže funkce input? V obou případech je nejlepší reakce ukončit program a informovat programátora, že (a kde) je něco špatně. Neboli vypat chybovou hlášku – to, co se stane normálně, bez try.

Další přílohy k try

Pro úplnost: kromě except existují dva jiné bloky, které můžeš „přilepit“ k try, a to else a finally. První se provede, když v try bloku žádná chyba nenastane; druhý se provede vždy – ať už chyba nastala nebo ne.

Můžeš taky použít více bloků except. Provede se vždy maximálně jeden: ten první, který danou chybu umí ošetřit.

try:
    neco_udelej()
except ValueError:
    print('Tohle se provede, pokud nastane ValueError')
except NameError:
    print('Tohle se provede, pokud nastane NameError')
except Exception:
    print('Tohle se provede, pokud nastane jiná chyba')
    # (kromě SystemExit a KeyboardInterrupt, ty chytat nechceme)
except TypeError:
    print('Tohle se neprovede nikdy')
    # ("except Exception" výše ošetřuje i TypeError; sem se Python nedostane)
else:
    print('Tohle se provede, pokud chyba nenastane')
finally:
    print('Tohle se provede vždycky; i pokud v `try` bloku byl např. `return`')

Vyvolání chyby

Občas se stane, že výjimku budeš potřebovat vyvolat sama.

Často se to stává když píšeš nějakou obecnou funkci. Třeba funkci na výpočet obsahu čtverce. Co se stane, když někdo zavolá obsah_ctverce(-5)?

  • Zadal-li ono -5 uživatel, je potřeba mu vynadat a zeptat se znovu.
  • Naměřil-li -5 nějaký robotický aparát, je potřeba ho líp zkalibrovat.
  • Vyšel-li čtverec se stranou -5 v nějakém výpočtu, je nejspíš potřeba opravit chybu v tom výpočtu.

Samotná funkce obsah_ctverce ale „neví“, proč ji někdo volá. Jejím úkolem je jen něco spočítat. Měla by být použitelná ve všech případech výše – a v mnoha dalších.

Když někdo zavolá obsah_ctverce(-5), neexistuje správný výsledek, který by funkce mohla vrátit. Místo vracení výsledku musí tato funkce signalizovat chybu. S tou se pak může program, který obsah_ctverce(-5) zavolal, vypořádat – vynadat uživateli, zkalibrovat měřák, nebo, pokud na chybu není připravený, sám skončit s chybou (a upozornit tak programátora, že je něco špatně).

Jak na to prakticky? Chybu můžeš vyvolat pomocí příkazu raise. Za příkaz dáš druh výjimky a pak do závorek nějaký popis toho, co je špatně.

def obsah_ctverce(strana):
    if strana > 0:
        return strana * strana
    else:
        raise ValueError(f'Strana musí být kladná, číslo {strana} kladné není!')

Podobně jako return, i příkaz raise ukončí funkci. A nejen tu – pokud na tuhle konkrétní chybu program předem připravený, ukončí se celý program.

Ze začátku není příliš důležité dumat nad tím, který typ výjimky je ten správný. Klidně „střílej od boku“. ValueError bývá často správná volba.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-pondeli:file:2",
      "title": "Výjimky",
      "html": "\n          \n    \n\n    <h1>V&#xFD;jimky</h1>\n<p>Poj&#x10F;me si prohloubit znalosti o chyb&#xE1;ch, neboli odborn&#x11B; o <em>v&#xFD;jimk&#xE1;ch</em>\n(angl. <em>exceptions</em>).</p>\n<p>Vezm&#x11B;me n&#xE1;sleduj&#xED;c&#xED; funkci:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">nacti_cislo</span><span class=\"p\">():</span>\n    <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"nb\">input</span><span class=\"p\">(</span><span class=\"s1\">&apos;Zadej &#x10D;&#xED;slo: &apos;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"p\">)</span>\n</pre></div><p>Kdy&#x17E; u&#x17E;ivatel nezad&#xE1; &#x10D;&#xED;slice, ale t&#x159;eba text <code>cokolada</code>,\nnastene v&#xFD;jimka jm&#xE9;nem <code>ValueError</code> (chyba hodnoty) a Python vyp&#xED;&#x161;e\nodpov&#xED;daj&#xED;c&#xED; chybovou hl&#xE1;&#x161;ku.</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\">3</span>, in <span class=\"n\">nacti_cislo</span>\n    <span class=\"n\">cislo</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"p\">)</span>\n<span class=\"gr\">ValueError</span>: <span class=\"n\">invalid literal for int() with base 10: &apos;cokolada&apos;</span>\n</pre></div><p>Program vol&#xE1; funkci <code>int()</code> pro neco, co ned&#xE1;v&#xE1; smysl jako &#x10D;&#xED;slo.\nCo s&#xA0;t&#xED;m m&#xE1; chud&#xE1;k funkce <code>int</code> d&#x11B;lat?\nNen&#xED; &#x17E;&#xE1;dn&#xE1; rozumn&#xE1; hodnota, kterou by mohla vr&#xE1;tit.\nP&#x159;ev&#xE1;d&#x11B;n&#xED; tohoto textu na cel&#xE9; &#x10D;&#xED;slo ned&#xE1;v&#xE1; smysl.</p>\n<p>A&#x17E; funkce <code>nacti_cislo</code> nejl&#xED;p &#x201E;v&#xED;&#x201C;, co se m&#xE1; st&#xE1;t, kdy&#x17E; u&#x17E;ivatel nezad&#xE1;\n&#x10D;&#xED;slice.\nSta&#x10D;&#xED; se u&#x17E;ivatele zeptat znovu!\nKdybychom m&#x11B;li funkci, kter&#xE1; zjist&#xED; jestli jsou v &#x159;et&#x11B;zci jen &#x10D;&#xED;slice,\nmohlo by to fungovat n&#x11B;jak takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">nacti_cislo</span><span class=\"p\">():</span>\n    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"nb\">input</span><span class=\"p\">(</span><span class=\"s1\">&apos;Zadej &#x10D;&#xED;slo: &apos;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">obsahuje_jen_cislice</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"p\">)</span>  <span class=\"c1\"># m&#xE1;me v&#xFD;sledek, funkce kon&#x10D;&#xED;</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;To nebylo &#x10D;&#xED;slo!&apos;</span><span class=\"p\">)</span>\n            <span class=\"c1\"># ... a zept&#xE1;me se znovu -- cyklus `while` pokra&#x10D;uje</span>\n</pre></div><p>Kde ale vz&#xED;t funkci <code>obsahuje_jen_cislice</code>?\nNechceme ji ps&#xE1;t znovu &#x2013; funkce <code>int</code> sama nejl&#xED;p pozn&#xE1;, co se d&#xE1; p&#x159;ev&#xE9;st na\n&#x10D;&#xED;slo a co ne.\nA dokonce n&#xE1;m to d&#xE1; v&#x11B;d&#x11B;t &#x2013; chybou, kterou m&#x16F;&#x17E;eme <em>zachytit</em>.</p>\n<h2>O&#x161;et&#x159;en&#xED; chyby</h2>\n<p>Pro zachycen&#xED; chyby m&#xE1; Python p&#x159;&#xED;kaz <code>try</code>/<code>except</code>.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">nacti_cislo</span><span class=\"p\">():</span>\n    <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n        <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"nb\">input</span><span class=\"p\">(</span><span class=\"s1\">&apos;Zadej &#x10D;&#xED;slo: &apos;</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;To nebylo &#x10D;&#xED;slo!&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Jak to funguje?\nP&#x159;&#xED;kazy v&#xA0;bloku uvozen&#xE9;m p&#x159;&#xED;kazem <code>try</code> se norm&#xE1;ln&#x11B; prov&#xE1;d&#x11B;j&#xED;, ale kdy&#x17E;\nnastane uveden&#xE1; v&#xFD;jimka, Python p&#x159;esko&#x10D;&#xED; zbytek bloky <code>try</code> a provede v&#x161;echno \nv&#xA0;bloku <code>except</code>.\nPokud v&#xFD;jimka nenastala, p&#x159;esko&#x10D;&#xED; se cel&#xFD; blok <code>except</code>.</p>\n<h2>Druhy chyb</h2>\n<p>A co je to <code>ValueError</code>? To je typ chyby.\nPodobn&#xFD;ch typ&#x16F; je spousta.\nV&#x161;echny jsou popsan&#xE9; <a href=\"https://docs.python.org/3/library/exceptions.html#exception-hierarchy\">v&#xA0;dokumentaci</a>; pro n&#xE1;s jsou (nebo budou) d&#x16F;le&#x17E;it&#xE9; tyto:</p>\n<div class=\"highlight\"><pre><code>BaseException\n &#x251C;&#x2500;&#x2500; SystemExit                     vyvol&#xE1;na funkc&#xED; exit()\n &#x251C;&#x2500;&#x2500; KeyboardInterrupt              vyvol&#xE1;na po stisknut&#xED; Ctrl+C\n &#x2570;&#x2500;&#x2500; Exception\n      &#x251C;&#x2500;&#x2500; ArithmeticError\n      &#x2502;    &#x2570;&#x2500;&#x2500; ZeroDivisionError    d&#x11B;len&#xED; nulou\n      &#x251C;&#x2500;&#x2500; AssertionError            nepoveden&#xFD; p&#x159;&#xED;kaz `assert`\n      &#x251C;&#x2500;&#x2500; AttributeError            neexistuj&#xED;c&#xED; atribut/metoda, nap&#x159;. &apos;abc&apos;.len\n      &#x251C;&#x2500;&#x2500; ImportError               nepoveden&#xFD; import\n      &#x251C;&#x2500;&#x2500; LookupError\n      &#x2502;    &#x2570;&#x2500;&#x2500; IndexError           neexistuj&#xED;c&#xED; index, nap&#x159;. &apos;abc&apos;[999]\n      &#x251C;&#x2500;&#x2500; NameError                 pou&#x17E;it&#xED; neexistuj&#xED;c&#xED;ho jm&#xE9;na prom&#x11B;nn&#xE9;\n      &#x2502;    &#x2570;&#x2500;&#x2500; UnboundLocalError    pou&#x17E;it&#xED; prom&#x11B;nn&#xE9;, kter&#xE1; je&#x161;t&#x11B; nebyla nastaven&#xE1;\n      &#x251C;&#x2500;&#x2500; SyntaxError               &#x161;patn&#xE1; syntaxe, program je ne&#x10D;iteln&#xFD;/nepou&#x17E;iteln&#xFD;\n      &#x2502;    &#x2570;&#x2500;&#x2500; IndentationError     &#x161;patn&#xE9; odsazen&#xED;\n      &#x2502;         &#x2570;&#x2500;&#x2500; TabError        kombinov&#xE1;n&#xED; mezer a tabul&#xE1;tor&#x16F; v odsazen&#xED;\n      &#x251C;&#x2500;&#x2500; TypeError                 &#x161;patn&#xFD; typ, nap&#x159;. len(9)\n      &#x2570;&#x2500;&#x2500; ValueError                &#x161;patn&#xE1; hodnota, nap&#x159;. int(&apos;xyz&apos;)</code></pre></div><p>Kdy&#x17E; odchyt&#xE1;v&#xE1;&#x161; obecnou v&#xFD;jimku,\nchytnou se i v&#x161;echny pod&#x159;&#xED;zen&#xE9; typy v&#xFD;jimek &#x2013;\nnap&#x159;&#xED;klad <code>except ArithmeticError:</code> zachyt&#xED; i <code>ZeroDivisionError</code>.\nA <code>except Exception:</code> zachyt&#xED; <em>v&#x161;echny</em> v&#xFD;jimky, kter&#xE9; b&#x11B;&#x17E;n&#x11B; chce&#x161; zachytit.</p>\n<h2>Nechytej je v&#x161;echny!</h2>\n<p>V&#x11B;t&#x161;inu chyb <em>nen&#xED;</em> pot&#x159;eba o&#x161;et&#x159;ovat.</p>\n<p>Nastane-li <em>ne&#x10D;ekan&#xE1;</em> situace, je t&#xE9;m&#x11B;&#x159; v&#x17E;dy\nmnohem lep&#x161;&#xED; program ukon&#x10D;it, ne&#x17E; se sna&#x17E;it\npokra&#x10D;ovat d&#xE1;l po&#x10D;&#xED;tat se &#x161;patn&#xFD;mi hodnotami.\nNav&#xED;c chybov&#xFD; v&#xFD;stup, kter&#xFD; Python standardn&#x11B;\np&#x159;iprav&#xED;, m&#x16F;&#x17E;e hodn&#x11B; uleh&#x10D;it hled&#xE1;n&#xED; chyby.</p>\n<p>Zachyt&#xE1;vej tedy jenom ty chyby, kter&#xE9; <em>o&#x10D;ek&#xE1;v&#xE1;&#x161;</em> &#x2013; v&#xED;&#x161; p&#x159;esn&#x11B;, kter&#xE1; chyba m&#x16F;&#x17E;e\nnastat a pro&#x10D;, a m&#xE1;&#x161; mo&#x17E;nost spr&#xE1;vn&#x11B; zareagovat.</p>\n<p>V&#xA0;na&#x161;em p&#x159;&#xED;kladu to plat&#xED; pro <code>ValueError</code> z&#xA0;funkce <code>int</code>.</p>\n<p>Co ale d&#x11B;lat, kdy&#x161; u&#x17E;ivatel chce ukon&#x10D;it program a zm&#xE1;&#x10D;kne\n<kbd>Ctrl</kbd>+<kbd>C</kbd>?\nNebo kdy&#x17E; se mu porouch&#xE1; kl&#xE1;vesnice a sel&#x17E;e funkce <code>input</code>?\nV&#xA0;obou p&#x159;&#xED;padech je nejlep&#x161;&#xED; reakce ukon&#x10D;it program a informovat\nprogram&#xE1;tora, &#x17E;e (a kde) je n&#x11B;co &#x161;patn&#x11B;.\nNeboli vypat chybovou hl&#xE1;&#x161;ku &#x2013; to, co se stane norm&#xE1;ln&#x11B;, bez <code>try</code>.</p>\n<h2>Dal&#x161;&#xED; p&#x159;&#xED;lohy k&#xA0;<code>try</code></h2>\n<p>Pro &#xFA;plnost: krom&#x11B; <code>except</code> existuj&#xED; dva jin&#xE9; bloky,\nkter&#xE9; m&#x16F;&#x17E;e&#x161; &#x201E;p&#x159;ilepit&#x201C; k&#xA0;<code>try</code>, a to <code>else</code> a <code>finally</code>.\nPrvn&#xED; se provede, kdy&#x17E; v&#xA0;<code>try</code> bloku\n&#x17E;&#xE1;dn&#xE1; chyba nenastane; druh&#xFD; se provede v&#x17E;dy &#x2013; a&#x165;\nu&#x17E; chyba nastala nebo ne.</p>\n<p>M&#x16F;&#x17E;e&#x161; taky pou&#x17E;&#xED;t v&#xED;ce blok&#x16F; <code>except</code>. Provede se v&#x17E;dy maxim&#xE1;ln&#x11B; jeden:\nten prvn&#xED;, kter&#xFD; danou chybu um&#xED; o&#x161;et&#x159;it.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"n\">neco_udelej</span><span class=\"p\">()</span>\n<span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se provede, pokud nastane ValueError&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">except</span> <span class=\"ne\">NameError</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se provede, pokud nastane NameError&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se provede, pokud nastane jin&#xE1; chyba&apos;</span><span class=\"p\">)</span>\n    <span class=\"c1\"># (krom&#x11B; SystemExit a KeyboardInterrupt, ty chytat nechceme)</span>\n<span class=\"k\">except</span> <span class=\"ne\">TypeError</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se neprovede nikdy&apos;</span><span class=\"p\">)</span>\n    <span class=\"c1\"># (&quot;except Exception&quot; v&#xFD;&#x161;e o&#x161;et&#x159;uje i TypeError; sem se Python nedostane)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se provede, pokud chyba nenastane&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">finally</span><span class=\"p\">:</span>\n    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Tohle se provede v&#x17E;dycky; i pokud v `try` bloku byl nap&#x159;. `return`&apos;</span><span class=\"p\">)</span>\n</pre></div><h2>Vyvol&#xE1;n&#xED; chyby</h2>\n<p>Ob&#x10D;as se stane, &#x17E;e v&#xFD;jimku bude&#x161; pot&#x159;ebovat vyvolat sama.</p>\n<p>&#x10C;asto se to st&#xE1;v&#xE1; kdy&#x17E; p&#xED;&#x161;e&#x161; n&#x11B;jakou obecnou funkci.\nT&#x159;eba funkci na v&#xFD;po&#x10D;et obsahu &#x10D;tverce.\nCo se stane, kdy&#x17E; n&#x11B;kdo zavol&#xE1; <code>obsah_ctverce(-5)</code>?</p>\n<ul>\n<li>Zadal-li ono <code>-5</code> u&#x17E;ivatel, je pot&#x159;eba mu vynadat a zeptat se znovu.</li>\n<li>Nam&#x11B;&#x159;il-li <code>-5</code> n&#x11B;jak&#xFD; robotick&#xFD; apar&#xE1;t, je pot&#x159;eba ho l&#xED;p zkalibrovat.</li>\n<li>Vy&#x161;el-li &#x10D;tverec se stranou <code>-5</code> v&#xA0;n&#x11B;jak&#xE9;m v&#xFD;po&#x10D;tu, je nejsp&#xED;&#x161; pot&#x159;eba opravit\nchybu v&#xA0;tom v&#xFD;po&#x10D;tu.</li>\n</ul>\n<p>Samotn&#xE1; funkce <code>obsah_ctverce</code> ale &#x201E;nev&#xED;&#x201C;, pro&#x10D; ji n&#x11B;kdo vol&#xE1;.\nJej&#xED;m &#xFA;kolem je jen n&#x11B;co spo&#x10D;&#xED;tat.\nM&#x11B;la by b&#xFD;t pou&#x17E;iteln&#xE1; ve v&#x161;ech p&#x159;&#xED;padech v&#xFD;&#x161;e &#x2013; a v&#xA0;mnoha dal&#x161;&#xED;ch.</p>\n<p>Kdy&#x17E; n&#x11B;kdo zavol&#xE1; <code>obsah_ctverce(-5)</code>, <em>neexistuje</em> spr&#xE1;vn&#xFD; v&#xFD;sledek, kter&#xFD; by\nfunkce mohla vr&#xE1;tit.\nM&#xED;sto vracen&#xED; v&#xFD;sledku mus&#xED; tato funkce <em>signalizovat chybu</em>.\nS&#xA0;tou se pak m&#x16F;&#x17E;e program, kter&#xFD; <code>obsah_ctverce(-5)</code> zavolal,\nvypo&#x159;&#xE1;dat &#x2013; vynadat u&#x17E;ivateli, zkalibrovat m&#x11B;&#x159;&#xE1;k, nebo, pokud na chybu nen&#xED;\np&#x159;ipraven&#xFD;, s&#xE1;m skon&#x10D;it s&#xA0;chybou (a upozornit tak program&#xE1;tora, &#x17E;e je n&#x11B;co\n&#x161;patn&#x11B;).</p>\n<p>Jak na to prakticky?\nChybu m&#x16F;&#x17E;e&#x161; vyvolat pomoc&#xED; p&#x159;&#xED;kazu <code>raise</code>.\nZa p&#x159;&#xED;kaz d&#xE1;&#x161; druh v&#xFD;jimky a pak do z&#xE1;vorek n&#x11B;jak&#xFD; popis toho, co je &#x161;patn&#x11B;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">obsah_ctverce</span><span class=\"p\">(</span><span class=\"n\">strana</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">strana</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">strana</span> <span class=\"o\">*</span> <span class=\"n\">strana</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"s1\">&apos;Strana mus&#xED; b&#xFD;t kladn&#xE1;, &#x10D;&#xED;slo {strana} kladn&#xE9; nen&#xED;!&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Podobn&#x11B; jako <code>return</code>, i p&#x159;&#xED;kaz <code>raise</code> ukon&#x10D;&#xED; funkci.\nA nejen tu &#x2013; pokud na tuhle konkr&#xE9;tn&#xED; chybu program p&#x159;edem p&#x159;ipraven&#xFD;,\nukon&#x10D;&#xED; se cel&#xFD; program.</p>\n<p>Ze za&#x10D;&#xE1;tku nen&#xED; p&#x159;&#xED;li&#x161; d&#x16F;le&#x17E;it&#xE9; dumat nad t&#xED;m, kter&#xFD; typ v&#xFD;jimky je ten\nspr&#xE1;vn&#xFD;.\nKlidn&#x11B; &#x201E;st&#x159;&#xED;lej od boku&#x201C;.\n<code>ValueError</code> b&#xFD;v&#xE1; &#x10D;asto spr&#xE1;vn&#xE1; volba.</p>\n\n\n        "
    }
  }
}