<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/screen.xsl" media="screen"?>
<lecture>

<meta>
  <maintitle>Python - strategie</maintitle>
  <author>Jiří Znamenáček</author>
  <title>Součet prvků seznamu</title>
  <date>2011-11-14</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="Úkol">

  <p>
    <strong>Úkol:</strong>
    Vraťte součet všech prvků v seznamu zadaném jako argument funkce.
  </p>

</slide>
<slide title="Rozbor">

  <p>
    Zamysleme se, co máme zadáno a co musíme udělat, abychom se dopracovali k řešení:
  </p>
  <ul>
    <li>Naším úkolem je napsat funkci, která bude vracet číslo.</li>
    <li>Toto číslo získá součtem prvků v seznamu, který bude dostávat jako vstupní parametr.</li>
    <li>Vracený součet si zřejmě musíme držet „bokem“ v nějaké proměnné. Přitom tato proměnná musí být na začátku nastavena na hodnotu 0, aby neovlivnila výsledný součet.</li>
  </ul>
  <p>
    Zkusme nyní postupně tyto body zapsat.
  </p>

</slide>
<slide title="Krok 1">

  <p>
    Naším prvním úkolem je vytvořit funkci vracející číslo:
  </p>
  <example lang="python">
    def sečti():
        return součet
  </example>
  <p>
    Jelikož jsme v Python'u, tedy dynamicky typovaném jazyce, uvedený kód bude fungovat do té doby, než se funkci <em>sečti()</em> pokusíme zavolat – v tu chvíli totiž interpretr zjistí, že se pokoušíme vracet proměnnou, které jsme nikde nepřiřadili žádnou hodnotu:
  </p>
  <example lang="text">
    NameError: global name 'součet' is not defined
  </example>
  <p>
    Upravme proto rovnou naši funkci takto:
  </p>
  <example lang="python">
    def sečti():
        součet = 0
        return součet
  </example>
  <p>
    Tohle už žádnou chybu nevyhodí a navíc to dává i rozumný smysl – nepošleme-li na vstup nic, je součtem nula.
  </p>

</slide>
<slide title="Krok 2">

  <p>
    Druhý bod předepisuje předání vstupního seznamu jako parametr funkce:
  </p>
  <example lang="python">
    def sečti(xs):
        součet = 0
        return součet
  </example>
  <p>
    A opět – jelikož jsme v Python'u, prostě pouze zapíšeme jméno parametru. Že je to seznam čísel k sečtení, se projeví až při zpracování kódu.
  </p>
  <note>
    A kdyby to náhodou nebyl seznam čísel, budou se dít úplně jiné věci ^_^
  </note>

</slide>
<slide title="Krok 3">

  <p>
    Posledním krokem je projít jednotlivé prvky seznamu a postupně je popřičítat k výstupní hodnotě. To zajistí nejsnáze univerzální smyčka <em>for-in</em>:
  </p>
  <example lang="python">
    def sečti(xs):
        součet = 0
        for x in xs:
            součet += x
        return součet
  </example>
  <note>
    Tohle už je funkční kus kódu. Zkuste si ho zavolat třeba jako <code>print( sečti([1, 2, 3, 4, 5, 6, 7,]) )</code>.
  </note>

</slide>
<slide title="Závěr I">

  <p>
    Výše zapsaná funkce <em>sečti()</em> plní naše zadání – vrací součet čísel ve vstupním seznamu. Ale má své – ostatně již pod čarou zmíněné – drobné mouchy:
  </p>
  <ul>
    <li>Smyčce <em>for-in</em> je srdečně jedno, po jakém typu bude iterovat. Pokud se po něm iterovat dá. (A že v Python'u se dá iterovat téměř po všem!)</li>
    <li>Operaci sčítání by také bylo celkem jedno, jaké typy se bude pokoušet skládat. Ale na začátku funkce přiřazujeme proměnné <em>součet</em> hodnotu <code>0</code>, tedy číslo, a proto se proti přičítání čehokoliv jiného bude urputně bránit.</li>
  </ul>
  <note>
    Ostatně zkuste si zavolat třeba <code>print( sečti(['a', 'b', 'c', 'd',]) )</code>.
  </note>
  
  <p>
    Lepší řešení by se tak dalo zapsat asi těmito dvěma různými způsoby:
  </p>
  <ol>
    <li>
      Ošetřit na začátku funkce, že vstupem je právě <em>seznam</em>, a to navíc seznam <em>čísel</em>, a pro jakýkoliv jiný vstup odmítnout spolupracovat.
      <note>
        Zde byste pravděpodobně skončili u nějaké varianty použití <a href="/materialy/python/exceptions/exceptions.xml?slajd=13">příkazu <code>assert</code></a>.
      </note>
    </li>
    <li>
      Pokusit se výpočet ve funkci nějakým způsobem provést pro libovolný vstup, který můžeme dostat. (Dostaneme tak „součet“ v nějakém zobecněném tvaru, ale to vůbec nemusí vadit.)
      <note>
        Například pro výše uvedený vstup „seznam znaků“ stačí nastavit počáteční hodnotu <code>součet = ''</code> a kód bude fungovat (vrátí řetězec znaků).
      </note>
    </li>
  </ol>
  <p>
    Mnoho funkcí a metod v Python'u se chová právě podle návrhu 2 – jsou napsány dostatečně obecně, aby se dokázaly „vypořádat“ se vstupy nejrůznějších (rozumných) druhů. (Pythoní hantýrkou se tomu říká „<em>duck typing</em>“.)
  </p>

</slide>
<slide title="Závěr II">

  <p>
      PS: Existuje mnohem jednodušší způsob jak v Python'u sečíst všechna čísla v seznamu – za pomoci vestavěné funkce <code>sum()</code> ^_~
  </p>

</slide>


</lecture>
