<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/screen.xsl" media="screen"?>
<lecture>

<meta>
  <maintitle>Python</maintitle>
  <author>Jiří Znamenáček</author>
  <title>Funkce</title>
  <date>2011-02-24</date>
  <link><!--a href="http://vyuka.ookami.cz" rel="external">http://vyuka.ookami.cz</a--></link>
</meta>
<!--
  „“–
  ↵ aneb &#x21B5; aneb \r aneb CR aneb CarriageReturn
-->


<slide title="Úvod">

  <p>
    Funkci v Python'u zavedeme pomocí klíčového slova <code>def</code>:
  </p>
  <example lang="python">
>>> def nic_nedělající_funkce():
...     pass
...
>>> nic_nedělající_funkce()
>>>
  </example>
  <note>
    Klíčové slovo <code>pass</code> je prázdná operace. Jelikož odsazování slouží v Python'u k určení těla bloku, použijeme <code>pass</code> často právě na místě, kde teprve kód dopíšeme.
  </note>
  
  <p>
    Trošku rozumnější příklad:
  </p>
  <example lang="python">
def celociselne_deleni_se_zbytkem(co, cim):
    """Vrať výsledek celočíselného dělení a též zbytek po něm."""
    return co // cim, co % cim

>>> vysledek = celociselne_deleni_se_zbytkem(13, 4)
>>> vysledek
(3, 1)
  </example>

</slide>
<slide title="Dokumentační řetězce">

  <p>
    Je dobrým zvykem na prvním místě těla funkce uvádět tzv. <em>dokumentační řetězec</em>. Má-li více než jednu řádku, je jeho ustálená podoba následující:
  </p>
  <example lang="python">
def f():
    """
    SUBJECT
    ↵
    BODY
    """
  </example>
  <p>
    Tyto <em>dokumentační řetězce</em> jsou součástí pythonovského kódu a dá se na ně programově dostat (čehož využívají některé nástroje a mimo jiné vestavěná funkce <code>help</code>):
  </p>
  <example lang="python">
>>> def f():
...     """
...     Nedělej nic, ale zdokumentuj to.
...
...     Skutečně, tato funkce nic nedělá. Ale její dokumentační část zabírá
...     více než jednu řádku.
...     """
...
>>> print( f.__doc__ )

        Nedělej nic, ale zdokumentuj to.

        Skutečně, tato funkce nic nedělá. Ale její dokumentační část zabírá
        více než jednu řádku.
  </example>

</slide>
<slide title="Poznámka">

  <p>
    Zatímco <em>dokumentační řetězec</em> je částí kódu a můžeme ho tudíž použít mimo jiné pro vytvoření jinak (zatím) prázdného těla funkce (tedy místo <code>pass</code>), s komentářem tomu tak nepřekvapivě již není:
  </p>
  <example lang="python">
>>> def f():
...     # prázdná funkce
...
  File "&lt;stdin>", line 3

    ^
IndentationError: expected an indented block
  </example>
  <p>
    Komentář z hlediska interpretru totiž vůbec neexistuje (je v kódu jen a jen pro nás) – místo bloku jsme tak vlastně nenapsali nic:
  </p>
  <example lang="python">
>>> def f():
...
  File "&lt;stdin>", line 2

    ^
IndentationError: expected an indented block
  </example>
  <p>
    Jinými slovy: <strong>Tam, kde je očekáván blok, musí blok být!</strong> Byť by byl vyroben právě jen pomocí <code>pass</code> nebo <em>dokumentačního řetězce</em>. 
  </p>

</slide>
<slide title="Návratová hodnota funkce">

  <p>
    V Python'u všechny funkce, které explicitně nic nevrací, vrací <code>None</code>:
  </p>
  <example lang="python">
>>> def f1():
...     pass
...
>>> f1()
>>> print( f1() )
None

>>> def f2():
...     return
...
>>> f2()
>>> print( f2() )
None
  </example>
  <note>
    V rámci výstupu interpretru je toto <code>None</code> potlačeno, pokud si ho explicitně pomocí <code>print</code> nevyžádáme.
  </note>

  <p>
    Pro srovnání zde je chování při explicitním vrácení jen a pouze právě <em>None</em>:
  </p>
  <example lang="python">
>>> def f3():
...     return None
...
>>> f3()
>>> print( f3() )
None
  </example>
  
  <p>
    Jinak ovšem funkce v Python'u mohou vracet prakticky cokoliv:
  </p>
  <example lang="python">
def f1():
    return "Ahoj, světe!"

def f2():
    return 2+2, "Baf!", [1, 'a', 3]
  </example>
  <!--note>
    Složitější návratovou strukturu si ovšem musíte na místě volání funkce zpracovat sami:
  </note-->

</slide>
<slide title="Argumenty poziční">

  <p>
    Funkce mohou mít argumenty. Ty se standardně předávají pozičně:
  </p>
  <example lang="python">
def f(a, b):
    print( "Argument 1: ", a )
    print( "Argument 2: ", b )

>>> f(1, 2)
Argument 1: 1
Argument 2: 2

>>> f('ahoj', 333)
Argument 1: ahoj
Argument 2: 333

>>> f('ahoj', (333, 'svět') )
Argument 1: ahoj
Argument 2: (333, 'svět')
  </example>
  <note>
    Jak je vidět, do argumentu může vstupovat libovolný pythonovský objekt.
  </note>

</slide>
<slide title="Argumenty pojmenované I">

  <p>
    Kromě <em>pozičních</em> argumentů můžeme s výhodou využít argumenty <em>pojmenované</em>. Zadávají se ve formě <em>keyword = value</em> a v nejjednodušším (a nejméně užitečném) případě slouží „pouze“ pro zpřehlednění volání funkce:
  </p>
  <example lang="python">
def celociselne_deleni_se_zbytkem(co, cim):
    return co // cim, co % cim

>>> celociselne_deleni_se_zbytkem(co=13, cim=4)
(3, 1)
  </example>

</slide>
<slide title="Argumenty pojmenované II">

  <p>
    Užitečnějším použitím jsou výchozí (<em>default</em>) hodnoty argumentů:
  </p>
  <example lang="python">
def mocneni(cislo, exponent=2):
    return cislo**exponent

# použije se výchozí hodnota pro parametr „exponent“
>>> mocneni(3)
9

# oba paramatry zadány pozičně
>>> mocneni(3, 3)
27

# druhý parametr zadán jménem
>>> mocneni(3, exponent=3)
27

# oba parametry zadány jménem
>>> mocneni(cislo=3, exponent=3)
27

# oba parametry zadány jménem, v jiném pořadí
>>> mocneni(exponent=3, cislo=3)
27
  </example>
  <note>
    Uvedený „trik“ používá spousta zabudovaných funkcí, např. funkce <code>round</code> pro zaokrouhlování reálných čísel na uvedený počet míst za desetinnou čárkou – neuvedete-li počet míst, výchozí hodnotou je 0:
    <example lang="python">
      >>> x = 3.141592753
      >>> round(x)
      3
      >>> round(x, 2)
      3.14
    </example>
  </note>

</slide>
<slide title="Argumenty pojmenované III">

  <p>
    Ale pozor – <strong>otočit pořadí pozičních a pojmenovaných argumentů už nemůžete</strong>:
  </p>
  <example lang="python">
def mocneni(cislo, exponent=2):
    return cislo**exponent

>>> mocneni(cislo=3, 3)
  File "&lt;stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
  </example>

</slide>
<slide title="Argumenty pojmenované IV">

  <p>
    Výchozí hodnotou pojmenovaného argumentu může být i odkaz na proměnnou, ale tyto <strong>odkazy se vyhodnucují ve chvíli definice funkce v aktuálním <em>defining scope</em></strong>.
  </p>
  <p>
    Dalším „průšvihem“ je, pokud jako parametr použijete proměnný (<em>mutable</em>) typ, ale to <a href="parameters.xml">probereme až později</a>.
  </p>

</slide>
<slide title="Poznámka">

    <p>
        Díky tomuto chování funkcí je možné v Python'u snadno napsat funkce, které přebírají libovolný počet vstupních pozičních argumentů a ještě navrch k tomu i řídicí parametry pojmenované. Přesně tak, jak to dělá například vestavěná funkce <a href="http://vyuka/materialy/python/cmd/print.xml"><em>print()</em></a>.
    </p>
    <p>
        Ale to není ani zdaleka všechno, co pythoní funkce se svými parametry umí. Mezi další oblíbené „triky“ patří například:
    </p>
    <ul>
        <li>
            <a href="parameters.xml?slajd=4">libovolný počet libovolných argumentů</a>
        </li>
        <li>
            <a href="parameters.xml?slajd=7">vynucení použití jména argumentu</a>
        </li>
        <li>
            <a href="parameters.xml?slajd=8">vynucení použití argumentu pouze pozicí</a>
        </li>
        <li>
            <a href="parameters.xml?slajd=14">memoizace s pomocí proměnných datových typů</a>
        </li>
    </ul>
    <p>
        Asi můžeme v klidu říci, že <strong>funkce jsou spolu s n-ticemi tou vůbec nejdůležitější součástí Python'u</strong>.
    </p>

</slide>


</lecture>
