<?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>Funkcionální prvky v Python'u</title>
  <date>2011-04-28</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>
    „Skutečný“ funkcionální jazyk nemá žádné proměnné – jednou přiřazené hodnoty jsou takovými už navždy. Podobně chování funkcí je zcela určeno pouze jejich vstupními parametry a navíc funkce nemění své okolí.
  </p>
  <p>
    Python nesplňuje žádnou z těchto podmínek. Dokonce byste asi měli docela problém napsat program bez použití proměnných. Ale svým protežováním iterovatelných sekvenčních typů se pojetí funkcionálních jazyků docela blíží. Dokonce pro práci s nimi nabízí kromě generátorové notace i několik speciálních funkcí.
  </p>
  <p>
    V dalším se podíváme na několik základních (nejen čistě) funkcionálních prvků jazyka Python.
  </p>

</slide>
<slide title="Generátorová notace">

  <p>
    Generátorová notace patří mezi jednu z nejtypičtějších pythoních konstrukcí. Umožňuje velmi snadno na místě jednoho řádku za pomoci členů sekvence vyrábět sekvence (seznamy, množiny a slovníky) jiné.
  </p>
  
  <p>
    Pro <em>seznam</em> má v principu dvě následující podoby (přičemž <em>PRVEK</em> je nejčastěji nějakou funkcí prvků procházené <em>SEKVENCE</em>):
  </p>
  <example lang="python">
    [ PRVEK for I in SEKVENCE ]
    [ PRVEK for I in SEKVENCE if PODMÍNKA ]
  </example>
  <note>
    Varianty pro množinu, resp. slovník, se liší pouze ve vnějších závorkách, resp. tvaru prvního členu (nepovinná část s podmínkou pro přehlednost vynechána):
    <example lang="python">
        { PRVEK for I in SEKVENCE }
        { KLÍČ:HODNOTA for I in SEKVENCE }
    </example>
  </note>

</slide>
<slide title="map(), filter() a spol.">

  <p>
    K typicky funkcionálním operacím patří operace prováděné nad celou sekvenční strukturou najednou.
  </p>
  <p>
    Přitom platí, že je-li možné výsledek operace určit dříve, než je prozkoumána sekvence celá, také se tak stane (takže se nepočítají zbytečné kroky).
  </p>

</slide>
<slide title="„any()“ &amp; „all()“">

  <p class="enumerate">
    Funkce <code>any(ITERABLE)</code> vrací <code>True</code>, je-li <em>alespoň jeden</em> prvek z iterovatelné struktury vyhodnocen jako pravdivý. Pro prázdnou strukturu vrací <code>False</code>:
  </p>
  <example lang="python">
>>> any('ahoj')
True

>>> any(['']*5)
False
  </example>

  <p class="enumerate">
    Funkce <code>all(ITERABLE)</code> vrací <code>True</code>, jsou-li <em>všechny</em> prvky z iterovatelné struktury vyhodnoceny jako pravdivé. Pro prázdnou strukturu vrací také <code>True</code>:
  </p>
  <example lang="python">
>>> all('ahoj')
True

>>> all(['a', 'h', 0, ''])
False
  </example>

</slide>
<slide title="„min()“ &amp; „max()“ &amp; „sum()“">

  <p class="enumerate">
    Funkce <code>min(SEKVENCE)</code> vrací <em>nejmenší</em> prvek ze sekvence:
  </p>
  <example lang="python">
>>> min([5, 2, 4, 3, 6])
2
  </example>
  <note>
    Pro více vstupních argumentů vrací nejmenší z nich. Nepovinný parametr <em>key</em> umožňuje určit řadicí funkci.
  </note>

  <p class="enumerate">
    Funkce <code>max(SEKVENCE)</code> vrací <em>největší</em> prvek ze sekvence:
  </p>
  <example lang="python">
>>> max([5, 2, 4, 3, 6])
6
  </example>
  <note>
    Pro více vstupních argumentů vrací největší z nich. Nepovinný parametr <em>key</em> umožňuje určit řadicí funkci.
  </note>

  <p class="enumerate">
    Funkce <code>sum(SEKVENCE)</code> vrací součet prvků v sekvenci:
  </p>
  <example lang="python">
>>> sum([5, 2, 4, 3, 6])
20
  </example>

</slide>
<slide title="„map()“ &amp; „filter()“">

  <p class="enumerate">
    Funkce <code>map(FUNKCE, ITERABLE)</code> vrací iterátor, který postupně mapuje funkci na jednotlivé prvky iterovatelné struktury:
  </p>
  <example lang="python">
>>> map(ord, 'ahoj')
&lt;map object at 0x01406710>
>>> list( map(ord, 'ahoj') )
[97, 104, 111, 106]
  </example>
  <p>
    Často je jednodušší a průhlednější napsat příslušný generátorový výraz <em>[f(x) for x in xs]</em>.
  </p>

  <p class="enumerate">
    Funkce <code>filter(FUNKCE, ITERABLE)</code> vrací iterátor, který postupně vrací ty prvky iterovatelné struktury, pro něž zadaná funkce poskytuje <code>True</code>:
  </p>
  <example lang="python">
>>> filter(lambda x: x % 2, [5, 2, 4, 3, 6])
&lt;filter object at 0x014085F0>
>>> list( filter(lambda x: x % 2, [5, 2, 4, 3, 6]) )
[5, 3]
  </example>
  <p>
    Pro funkci různou od <code>None</code> je často je jednodušší a průhlednější napsat příslušný generátorový výraz <em>[x for x in xs if f(x)]</em>.
  </p>
  
  <hr/>
  
  <p>
    Asi už nepřekvapí, že:
  </p>
  <example lang="python">
map(f, filter(p, xs))
  &lt;=>
[f(x) for x in xs if p(x)]
  </example>

</slide>
<slide title="„zip()“">

  <p>
    Funkce <code>zip(*ITERABLES)</code> vrací iterátor, který skládá dohromady do n-tic navzájem si odpovídající prvky z jednotlivých vstupních iterovatelných struktur:
  </p>
  <example lang="python">
>>> zip('ahoj', [5, 2, 3, 4])
&lt;zip object at 0x01400AF8>
>>> list( zip('ahoj', [5, 2, 3, 4]) )
[('a', 5), ('h', 2), ('o', 3), ('j', 4)]
  </example>
  <p>
    Přitom platí:
  </p>
  <ul>
    <li>
        <em>zip()</em> se vyčerpá na nejkratší dostupné sekvenci. Potřebujete-li opačné chování, použijte <code>itertools.zip_longest()</code>.
        <example lang="python">
            # a) nejkratší
            >>> list( zip('ahoj', [5, 2, 3, 4, 1]) )
            [('a', 5), ('h', 2), ('o', 3), ('j', 4)]
            
            # b) nejdelší
            >>> from itertools import zip_longest
            >>> list( zip_longest('ahoj', [5, 2, 3, 4, 1]) )
            [('a', 5), ('h', 2), ('o', 3), ('j', 4), (None, 1)]
            >>> list( zip_longest('ahoj', [5, 2, 3, 4, 1], fillvalue='X') )
            [('a', 5), ('h', 2), ('o', 3), ('j', 4), ('X', 1)]
        </example>
    </li>
    <li>
        Pro jednu vstupní sekvenci vrací jednoprvkové n-tice.
        <example lang="python">
            >>> list( zip('ahoj') )
            [('a',), ('h',), ('o',), ('j',)]
        </example>
    </li>
  </ul>

</slide>
<slide title="Modul „functools“">

  <p>
    Další funkcionální prostředky pro práci s funkcemi (<em>higher-order functions</em>) poskytuje modul <em>functools</em>. Jedná se o funkce, které operují nad funkcemi a v nějaké upravené podobě je vrací (tak trochu jako dekorátory; ostatně se většinou jako dekorátory používají).
  </p>
  <p>
    Jelikož uvedené si zaslouží probrat podrobněji, je mu věnována <a href="advanced-3.xml">samostatná přednáška</a>.
  </p>

</slide>
<slide title="Lambda-funkce">

  <p>
    Lambda-funkce jsou anonymní (tj. bezejmenné) funkce definované typicky v rámci jednoho řádku a skládající se pouze z jednoho výrazu, který je vyhodnocován ve chvíli volání funkce:
  </p>
  <example lang="python">
lambda [ARGUMENT[Y]]: VÝRAZ
  </example>

  <p>
    Pythonovské lambda-funkce jsou v porovnání s prakticky libovolnou jinou implementací velmi omezené – mohou obsahovat pouze jeden výraz, a to ještě bez složitějších, natožpak dokonce víceřádkových konstrukcí.
  </p>
  <p>
    Ve většině případů ale zastanou obdobnou práci „obyčejné“ funkce v Python'u, protože jsou tzv. <em>first-class object/citizen</em>. (Což především znamená, že je možné je předávat jako parametry do jiných funkcí, vracet je jako návratové hodnoty z funkcí a ukládat je v datových strukturách.)
  </p>

</slide>
<slide title="Generátory">

  <p>
    Naprosto typickým prvkem funkcionálního programování je vytváření (potenciálně i nekonečných) struktur, z nichž se vrací pouze ta část, která je aktuálně vyžadována, a nic dalšího se (zatím) nepočítá.
  </p>
  <p>
    V Python'u se konstruktorům takových objektů říká <strong>generátory</strong> a jelikož jsou velmi důležité, je jim věnována <a href="/materialy/python/generators/generators.xml">samostatná přednáška</a>.
  </p>

</slide>


</lecture>
