<?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>Py3k versus Python 2.x</title>
  <date>2016-10-09</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>
        Python je řekl bych zcela typický příklad <strong>oběti vlastního úspěchu</strong>. Třeba takové unicodové řetězce se do dvojkové řady dostaly hodně velkou oklikou a ještě jenom proto, že „všichni je používají a není to vůbec špatný nápad, dát je tam pořádně ale pro verzi 2.0 už nestihneme“. A to se psal zrovna rok 2000 a nikdo ještě netušil, že se z Pythonu'u stane doslova a dopísmene hit.
    </p>
    <p>
        Již v té době sílilo u BDFL a dalších klíčových vývojářů přesvědčení, že jazyk samotný – a systémová knihovna snad ještě víc – jim začíná přerůstat přes hlavu a že je třeba s tím něco udělat. A padlo rozhodnutí, kterého se v historii moc jiných jazyků/projektů neodvážilo (a když už, tak na něj většinou šeredně doplatily):
    </p>
    <blockquote>
        „Takhle už to dál nejde. Zkusíme to vzít (skoro) od základů a udělat to znovu a pořádně.“
    </blockquote>
    <p>
        Světlo světa tak spatřil jazyk <strong>Pyton 3.x</strong>, který je sice pořád ještě Python, ale podstatně elegantnější, chytřejší, nenucenější a vůbec mocnější. A mimo jiné také <strong>zpětně nekompatibilní</strong>.
    </p>
    <p>
        Osobně uvedený krok hodnotím pozitivně – jakmile si na trojkové „vychytávky“ zvyknete, pracovat s dvojkou je pak už jenom utrpení. Ovšem mít na uvedený vývoj vliv, přivítal bych mnohem radikálnější rozchod s historií – ve trojkové řadě totiž i přes zpětnou nekompatibilitu zůstala hromada blbostí a zbytečností, které se také měly poroučet na smetiště dějin.
    </p>

</slide>
<slide title="Poznámka k Python'u 2.7">

    <p>
        Navzdory původním tvrzením o prakticky nulové „backportaci“ novinek Python'u trojkového zpět do dvojkového toho za ty roky probublalo strašně moc.
    </p>
    <note>
        Oficiální zdůvodnění snad jest, že to usnadňuje psát kód pro dvojkovou i trojkovou řadu současně. Praktický efekt je spíš ten, že zarytí odpůrci trojky mají čím dál tím více důvodů, proč na trojku vůbec nepřecházet. Pokud tedy nepracují v mezinárodním jazykovém prostředí, tam je dvojka se svojí dualitou „osmibitový řetězec VERSUS unicodový řetězec“ pekelná.
    </note>
    <p>
        Takže se snadno může stát, že o nějaké věci tvrdím, že v Python'u dvojkovém nefunguje, zatímco v nějaké – dostatečně poslední – verzi řady 2.7 to tak vůbec už být nemusí.
    </p>

</slide>
<slide title="Python 3.x versus Python 2.x">
  
    <p>
        Kdybych se chtěl se změnami v trojkové verzi Python'u vypořádat OPRAVDU velmi zkrátka, napsal bych asi:
    </p>
    <ul>
        <li>
            Nejviditelnější změna:
            <example lang="python">
                print('Ahoj, Karle!')   # Python 3.x
                print 'Ahoj, Karle!'    # Python 2.x
            </example>
        </li>
        <li>
            Nejdůkladnější změna:
            <example lang="python">
                "Ahoj, světe!"    # Python 3.x
                u"Ahoj, světe!"   # Python 2.x
            </example>
        </li>
        <li>
            Iterátory jsou všude.
        </li>
        <li>
            Vyčištění systémové knihovny.
        </li>
    </ul>
    <p>
        Přitom na první věc se – řekl bych zcela zbytečně – nejvíc nadává, druhou všichni ignorují, než se poprvé spálí a pochopí, že to je ta zcela nejdůležitější věc, jaká se v celé historii Python'u stala, třetí je velmi příjemná změna v chování jazyka, na kterou se rychle a snadno zvyká (ve dvojkovém Python'u jsou iterátory také, ale musíte je chtít použít; ve trojkovém už jsou – většinou – jenom ony) a konečně čtvrtá vrátila do bažiny systémových modulů zase trochu řád.
    </p>
    <handout>
        <a class="external" href="http://python.org/doc/3.0.1/whatsnew/3.0.html">http://python.org/doc/3.0.1/whatsnew/3.0.html</a>
        <br/>
        <a class="external" href="http://python.org/doc/3.0.1/tutorial/index.html">http://python.org/doc/3.0.1/tutorial/index.html</a>
    </handout>

</slide>
<slide title="Kódování řetězců">

    <p>
        Začnu rovnou tím nejdůležitějším – způsobem uchovávání řetězců v paměti.
    </p>

    <p class="py3k">
        V trojkovém Python'u už to asi ani snažší být nemůže – napíšete-li někde typ řetězec (tedy cokoliv v nějaké z <a href="/materialy/python/types/strings.xml">mnoha variant jednoduchých a dvojtých uvozovek</a>), tak neřeknete-li v hlavičce (viz <a href="?slajd=5">následující slajd</a>) kdovíproč jinak, <strong>Python automaticky předpokládá, že jde o textová data v kódování UTF-8</strong>.
    </p>

    <p class="py2k">
        Zato v Python'u dvojkovém na vás čeká pěkný podraz – <strong>řetězce jsou totiž dvojího druhu</strong>:
    </p>
    <ul>
        <li>
            <strong>řetězce unicodové</strong>, značené jako <code>u""</code> nebo <code>U""</code>;
        </li>
        <li>
            <strong>„řetězce“ osmibitové</strong>, značené jako <code>""</code>.
        </li>
    </ul>
    <note>
        Plus samozřejmě všechny jejich varianty s apostrofy, případně i trojtým opakováním.
    </note>
    <p>
        Přitom platí, že tyhle <strong>dvojkové pseudořetězce se berou buď jako sekvence bajtů, pokud tomu tak konzument chce, nebo jako řetězce textové, pokud má někdo zrovna zájem, pak ale</strong>:
    </p>
    <ul>
        <li>
            Při uvedení hlavičky kódování zdrojového souboru (např. <code># encoding: utf-8</code>) se osmibitové řetězce vyhodnucují v tomto kódování.
        </li>
        <li>
            <strong>Bez uvedení hlavičky kódování zdrojového souboru se osmibitové řetězce vyhodnocují ve výchozím kódování systému, na kterém skript zrovna běží.</strong>
        </li>
    </ul>
    <p>
        Každému je asi jasné, že je zaděláno na pořádný průšvih. Pokud tedy nepíšete všechno jen a pouze jenom jako ASCII…
    </p>

</slide>
<slide title="Intermezzo – Kódování zdrojových textů">

    <p class="py3k">
        V trojkovém Python'u je to (relativně) jednoduché, ten v základním nastavení <strong>trvá na UTF-8</strong> skoro všude, tudíž i kódování zdrojových textů, a vaše smůla, když se třeba zrovna budete pokoušet psát zdrojový kód v kódování jiném.
    </p>

    <p class="py2k">
        V Python'u dvojkovém už v tuto chvíli asi nikoho nepřekvapí, že <strong>výchozím kódováním zdrojových souborů je aktuální/výchozí kódování celého systému</strong>! Což mimo jiné znamená:
    </p>
    <ul>
        <li>
            Umožňuje-li vaše systémové kódování zápis „netradičních“ znaků (jako jsou například česká nabodeníčka :-), můžete je vesele použít uvnitř <em>osmibitových řetězců</em> <code>""</code>. Běda vám, když takový zdroják ale zkusí otevřít někdo, jehož systémové kódování to neumožňuje…
        </li>
        <li>
            Abyste se vyhnuli předchozímu problému, používáte <em>řetězce unicodové</em> <code>u""</code> (nebo <code>U""</code>). To vás většinou už donutí nějaké rozumné kódování pro zápis zdrojového textu vybrat (například pomocí hlavičky <code># encoding: utf-8</code>).
            <note>
                Python zkousne téměř libovolný popis, pokud v něm někde na začátku bude podřetězec <em>coding</em> a na konci identifikace příslušného kódování.
            </note>
        </li>
    </ul>
    <p>
        PS: Hodně štěstí s přenosem zdrojáků, pokud jsou v nich „řetězce“ s neASCII-znaky. Nebo vůbec hodně štěstí s používáním knihoven, které napsal někdo, komu <em>u""</em> nic neříká.
    </p>

</slide>
<slide title="Kódování řetězců – Py2k">

    <p class="enumerate">
        Oba druhy řetězců – osmibitové a unicodové – můžete ve dvojkovém Python'u mimo jiné třebas i skládat:
    </p>
    <example lang="python">
        >>> "ahoj " + u"světe"
        u'ahoj světe'
    </example>

    <p class="enumerate">
        Jenže daleko horší je, že funkce akceptující na vstupu „obyčejné“ řetězce <code>""</code> si mohou s tímto vstupem dělat, co je zrovna napadne – někdy předpokládají, že jde o sekvenci bajtů, tedy v podstatě binární data, jindy se zase můžou k vaší hrůze rozhodnout, že jde o text ve výchozím kódování toho kterého systému!
    </p>
    <p>
        Je jasné, že tohle je skutečně pořádný průšvih. Kterému se dá „vyhnout“ jedině tak, že se pohybujete pouze na úrovni ASCII (tedy vlastně sedmi bitů), kde jsou oba druhy řetězců v podstatě zaměnitelné.
    </p>
    <note>
        Převádět takový kód, aby fungoval pod trojkovým Python'em, není vůbec žádný med, jak vás ostatně snadno přesvědčí třebas Mark Pilgrim ve svém <a href="http://www.diveintopython3.net/whats-new.html" class="external">Dive Into Python 3</a>. Ovšem výsledek je miliónkrát lepší.
    </note>


</slide>
<slide title="Názvy souborů">

    <p>
        Další místo, kde se můžete kopnout do vlastní paty, ale tentokrát kupodivu spíše na straně Python'u 3.x, jsou názvy souborů na souborovém systému. A na vině jsou tentokráte tak trochu UNIXy, protože jsou prostě staré. (Což ovšem neznamená, že Python 3.x pro někoho věci oproti dvojkové řadě značně zkomplikoval.)
    </p>
    <p class="py3k">
        Celý problém spočívá v tom, že zatímco většina moderních operačních systémů názvy souborů ukládá v Unicodu (nebo alespoň pomocí jasně definovaného API), v Linuxu a jinde uvedené API akceptuje <strong>prakticky zcela libovolnou sekvenci prakticky jakýchkoli bajtů</strong>. Co to znamená pro trojkový Python, který se snaží seč může předstírat, že všechno je Unicode, je asi celkem jasné. Na druhou stranu uživatelé Windows a dokonce i Mac OS X jsou za vodou.
    </p>

</slide>
<slide title="PS – textové soubory">

    <p>
        Jen tak na okraj – napíšete-li..
    </p>
    <example lang="python">
        f = open('soubor.txt')
    </example>
    <p>
        ..dvojkový i trojkový Python se bohužel vzácně shodnou, že <strong>místo neuvedeného explicitního kódování zpracovávaného textového souboru se použije systémové</strong> :-( Opět hodně štěstí při „snadném“ sdílení zdrojových kódů mezi systémy s jiným výchozím kódováním…
    </p>
    <p class="py23k">
        Mimochodem tady už náprava snadná není: Zatímco ve trojkovém Python'u má funkce <em>open()</em> nepovinný parametr <em>encoding</em>, který trable s přenositelností vyřeší (alespoň než zakopnete o <a href="/materialy/python/pitfalls.xml?slajd=6">Unicode, který není tak úplně Unicode</a>), v Python'u dvojkovém musíte na pomoc zavolat úplně jiný modul, konkrétně <em>codecs.open()</em>. <em>„Happy coding!“</em>
    </p>

</slide>
<slide title="Celá čísla dlouhá vs krátká">

    <p class="py3k">
        Ve trojkovém Python'u jsou jedna jediná celá čísla, a to „nafukovací“ (tedy <em>dlouhá</em>). Prostě jak velké číslo je potřeba, tak velké se zabere (pokud se vleze někam do paměti samozřejmě):
    </p>
    <example lang="python">
        >>> 10**18
        1000000000000000000
        >>> 10**23
        100000000000000000000000
    </example>

    <p class="py2k">
        V Python'u dvojkovém existují i celá čísla <em>krátká</em> a ta dlouhá se pak označují postfixem <code>L</code> (jde i <code>l</code>, ale to se snadno plete s jedničkou) a mají vlastní konstruktor <em>long()</em>:
    </p>
    <example lang="python">
        >>> sys.maxint
        9223372036854775807
        >>> 10**18
        1000000000000000000
        >>> 10**23
        100000000000000000000000L
    </example>
    <p>
        Práce s <em>krátkými</em> je celkem pochopitelně systémově méně náročná, ale kdo na to má pořád dávat pozor, že.
    </p>
    <note>
        Ostatně kdo chce psát v čistém Python'u extrémně rychlé programy, asi si vybral špatný jazyk ^_~
    </note>

</slide>
<slide title="Dělení">

    <p class="py3k">
        Ve trojkovém Python'u dělení operátorem <code>/</code> pro celá čísla vrací, co by člověk čekal, a když chceme dělit celočíselně, použijeme operátor <code>//</code>. Tedy žádné překvapení na nás nečeká:
    </p>
    <example lang="python">
        >>> 1 / 2
        0.5
        >>> 1 // 2
        0
        >>> 1.0 // 2
        0.0
    </example>

    <p class="py2k">
        To v Python'u dvojkovém se asi nebudete stačit divit:
    </p>
    <example lang="python">
        >>> 1 / 2
        0
        >>> 1.0 / 2
        0.5
    </example>
    <p>
        Nejvtipnější (nebo nejsmutnější?) na tom je, že operátor <code>//</code> je tam také a chová se očekávaně:
    </p>
    <example lang="python">
        >>> 1 // 2
        0
        >>> 1.0 // 2
        0.0
    </example>

</slide>
<slide title="Oktalová čísla">

    <p class="py3k">
        Když už jsme u té konzistence – v trojce všechno krásně sedí..
    </p>
    <example lang="python">
        >>> hex(65)
        '0x41'
        >>> oct(65)
        '0o101'
        >>> bin(65)
        '0b1000001'
    </example>

    <p class="py2k">
        ..ale běda vám ve dvojce!
    </p>
    <example lang="python">
        >>> hex(65)
        '0x41'
        >>> oct(65)
        '0101'
        >>> bin(65)
        '0b1000001'
    </example>
    <p>
        No kdo se v tom má vyznat?
    </p>

</slide>
<slide title="Iterátory – „range“">

    <p class="py3k">
        Ve trojkovém Python'u je rozsah prostě rozsahem..
    </p>
    <example lang="python">
        >>> range(10)
        range(0, 10)
    </example>
    <p>
        ..a dokud po něm nezačnete iterovat, tak se nic víc nedozvíte.
    </p>

    <p class="py2k">
        Ve dvojkovém Python'u je rozsah na druhou stranu obyčejným seznamem..
    </p>
    <example lang="python">
        >>> range(10)
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    </example>
    <p>
        ..po kterém se ovšem z hlediska prvků iteruje zdánlivě stejným způsobem. Rozdíl spočívá v tom, že všechny ty prvky zabírají místo v paměti. Chcete-li ve dojkovém Python'u stejné iterátorové chování jako ve trojce, musíte použít konstruktor <em>xrange()</em>.
    </p>

</slide>
<slide title="Iterátory – slovníky">

    <p class="py3k">
        Podobně byly změněny i slovníky – ve trojce se po nich iteruje..
    </p>
    <example lang="python">
        >>> xs = {1: 'a', 2: 'b', 3: 'c'}
        >>> xs.keys()
        dict_keys([1, 2, 3])
        >>> xs.values()
        dict_values(['a', 'b', 'c'])
        >>> xs.items()
        dict_items([(1, 'a'), (2, 'b'), (3, 'c')])
    </example>

    <p class="py2k">
        ..zatímco ve dvojce dostaneme seznamy:
    </p>
    <example lang="python">
        >>> xs = {1: 'a', 2: 'b', 3: 'c'}
        >>> xs.keys()
        [1, 2, 3]
        >>> xs.values()
        ['a', 'b', 'c']
        >>> xs.items()
        [(1, 'a'), (2, 'b'), (3, 'c')]
    </example>
    <p>
        Pokud tedy nepoužijete příslušné iterátorové varianty <em>xs.iterkeys()</em>, <em>xs.itervalues()</em> a <em>xs.iteritems()</em>.
    </p>

</slide>
<slide title="Iterátory – „zip“">

    <p class="py3k">
        Nepřekvapivě stejnou iterátorovou změnou prošla do trojky i funkce <em>zip</em>:
    </p>
    <example lang="python">
        >>> zip('abc', 'abcd')
        &lt;zip object at 0x7f7c86af0c88>
    </example>

    <p class="py2k">
        Ve dvojkovém Python'u dostanete seznam:
    </p>
    <example lang="python">
        >>> zip('abc', 'abcd')
        [('a', 'a'), ('b', 'b'), ('c', 'c')]
    </example>
    <p>
        A zase – z hlediska iterace po prvcích objektu je výsledek stejný, ale prakticky ani filozoficky se vůbec nejedná o totéž. Iterátorovou variantu nepřekvapivě k dispozici máme, ale pěkně schovanou jako <em>itertools.izip()</em>.
    </p>

</slide>
<slide title="Iterátory – „map“">

    <p class="py3k">
        Asi nikoho už nepřekvapí, že funkce <em>map</em> je ve trojkovém Python'u iterátor..
    </p>
    <example lang="python">
        >>> map(lambda x,y: x+y, 'abc', 'abcd')
        &lt;map object at 0x7f7c86af2400>
    </example>

    <p class="py2k">
        ..zatímco ve dvojkovém Python'u dostaneme opět seznam:
    </p>
    <example lang="python">
        >>> map(lambda x,y: x+y, 'abc', 'abc')
        ['aa', 'bb', 'cc']
    </example>
    <note>
        A to ještě podle verze buď dokáže nebo nedokáže zpracovat nestejně dlouhé vstupy.
    </note>
    <p>
        A zase – je k dispozici i iterátorová varianta <em>itertools.imap()</em>.
    </p>

</slide>
<slide title="Iterátory – „filter“">

    <p class="py3k">
        A kdo si myslel, že funkce <em>filter</em> zůstala „ušetřena“ ^_~, samozřejmě se mýlil:
    </p>
    <example lang="python">
        >>> filter(lambda x: ord(x) > 91, 'AbCd')
        &lt;filter object at 0x7f7c86af2438>
    </example>

    <p class="py2k">
        Ve dvojkovém Python'u obdržíme rovnou výsledek:
    </p>
    <example lang="python">
        >>> filter(lambda x: ord(x) > 91, 'AbCd')
        'bd'
    </example>
    <p>
        Pokud nepoužijete iterátorovou variantu <em>itertools.ifilter()</em>.
    </p>

</slide>
<slide title="Iterátory – „next()“ a „__next__()“">

    <p class="py3k">
        Když už jsme u iterátorů – další prvek sekvence se v trojkovém Python'u vyvolává pomocí vestavěné funkce <em>next()</em>, která nepřekvapivě volá magickou metodu <em>__next__()</em> objektu iterátoru:
    </p>
    <example lang="python">
        >>> xs = 'ahoj'
        >>> i = xs.__iter__()   # ve skutečnosti by se volalo „iter(xs)“
        >>> i.__next__()        # ve skutečnosti by se volalo „next(i)“
        'a'
    </example>

    <p class="py2k">
        Ve dvojkovém Python'u se metoda iterátoru jmenovala pro zmatení nepřítele naprosto nemagicky <em>Iterátor.next()</em>, i když konstruktor iterátoru byl očekávaně magicky <em>Iterátor.__iter__()</em>:
    </p>
    <example lang="python">
        >>> xs = 'ahoj'
        >>> i = xs.__iter__()
        >>> i.next()
        'a'
    </example>

</slide>
<slide title="Generátorová notace">

    <p class="py3k">
        Zatímco v Python'u trojkovém můžete generovat seznamy, množiny i slovníky..
    </p>
    <example lang="python">
        >>> [x for x in "abeceda"]
        ['a', 'b', 'e', 'c', 'e', 'd', 'a']
        >>> {x for x in "abeceda"}
        {'c', 'e', 'a', 'b', 'd'}
        >>> {i:x for i,x in enumerate("abeceda")}
        {0: 'a', 1: 'b', 2: 'e', 3: 'c', 4: 'e', 5: 'd', 6: 'a'}
    </example>

    <p class="py2k">
        ..ve dvojkovém jste omezeni pouze na seznamy:
    </p>
    <example lang="python">
        >>> [x for x in "abeceda"]
        ['a', 'b', 'e', 'c', 'e', 'd', 'a']
    </example>
    <note>
        A jako vždy – od nějaké dva-sedmičkové verze už to není pravda a jsou tam i ty zbylé dvě.
    </note>

</slide>
<slide title="„!=“ vs „&lt;&gt;“">

    <p class="py3k">
        Test nerovnosti dvou hodnot je ve trojkovém Python'u zapisován operátorem <code>!=</code>..
    </p>
    <example lang="python">
        >>> 2 != 3
        True
    </example>
    <p class="py2k">
        ..zatímco v Python'u dvojkovém lze z historických důvodů použít ještě i operátor <code>&lt;&gt;</code>:
    </p>
    <example lang="python">
        >>> 2 &lt;&gt; 3
        True
        >>> 2 != 3
        True
    </example>

</slide>
<slide title="Porovnávání hodnot">

    <p class="py2k">
        Při porovnávání hodnot provádí Python 2.x implicitní konverzi typů..
    </p>
    <example lang="python">
        >>> 2 &lt; '1'
        True
    </example>
    <p>
        ..nebo dokonce vyloženě páchá magii:
    </p>
    <example lang="python">
        >>> len &lt; len
        False
    </example>
    <p>
        Dává vám to smysl? Asi moc ne, že. Tudíž není moc divu, že..
    </p>

    <p class="py3k">
        ..ve trojce už nic takového není:
    </p>
    <example lang="python">
        >>> 2 &lt; '1'
        Traceback (most recent call last):
          File "&lt;stdin>", line 1, in &lt;module>
        TypeError: unorderable types: int() &lt; str()

        >>> len &lt; len
        Traceback (most recent call last):
          File "&lt;stdin>", line 1, in &lt;module>
        TypeError: unorderable types: builtin_function_or_method() &lt; builtin_function_or_method()
    </example>
    <note>
        Čimž samozřejmě netvrdím, že vaše objekty (či dokonce funkce) se porovnávat nedají, protože <a href="/materialy/python/sorting/advanced.xml">dají, když budete chtít</a>.
    </note>

</slide>
<slide title="Řazení objektů">

    <p class="py3k">
        Trojkový Python zavedl – jako doplněk k základnímu lexikografickému způsobu – pro řazení objektů velmi mocný parametr <em>key</em>:
    </p>
    <example lang="python">
        >>> xs = [ ('Láďa', 2), ('Jana', 1), ('Karel', 3) ]
        >>> sorted(xs)
        [('Jana', 1), ('Karel', 3), ('Láďa', 2)]
        >>> sorted(xs, key=lambda x: x[1])
        [('Jana', 1), ('Láďa', 2), ('Karel', 3)]
    </example>

    <p class="py2k">
        V Python'u dvojkovém je k dispozici „klasická“ varianta pomocí porovnávací funkce za parametrem <em>cmp</em>:
    </p>
    <example lang="python">
>>> xs = [ (u'Láďa', 2), ('Jana', 1), ('Karel', 3) ]
>>> sorted(xs)
[('Jana', 1), ('Karel', 3), (u'L\xe1\u010fa', 2)]
>>> sorted(xs, cmp=lambda x,y: x[1] - y[1])
[('Jana', 1), (u'L\xe1\u010fa', 2), ('Karel', 3)]
    </example>
    <note>
        Byť v posledních verzích dva-sedmičkové řady funguje i <em>key</em>.
    </note>

</slide>
<slide title="„True + True“">

    <p class="py3k">
        I ve trojkovém Python'u jde pořád udělat následující..
    </p>
    <example lang="python">
        >>> True + True
        2
    </example>
    <p>
        ..protože <em>Boolean</em> je jenom podtyp <em>int</em>. Na druhou stranu už nejdou aspoň pravdivostní identifikátory přepsat:
    </p>
    <example lang="python">
        >>> True = 'ahoj'
          File "&lt;stdin>", line 1
        SyntaxError: can't assign to keyword
    </example>
    <p class="py2k">
        Ve dvojkovém Python'u to ovšem ještě klíčová slova nejsou:
    </p>
    <example lang="python">
        >>> True + True
        2
        >>> True = 'ahoj'
        >>> True + True
        'ahojahoj'
    </example>

</slide>
<slide title="Bublání ven proměnných generátorové notace">

    <p class="py2k">
        Následující vlastnost dvojkové řady je skutečný podraz <i>par excellence</i>:
    </p>
    <example lang="python">
        >>> [x for x in range(5)]
        [0, 1, 2, 3, 4]
        >>> x
        4
    </example>
    <p>
        Co heršoft dělá pomocná proměnná z generátoru seznamu v globálním kontextu?!? Ano, já vím, u smyček <em>for-in</em> ta proměnná také vybublá ven, ale tam se to dá snad i skoro čekat (byť <a href="/materialy/python/pitfalls.xml?slajd=10">netvrdím</a>, že je to očekávané chování) a rozhodně snáze na to zvyknout.
    </p>
    <p class="py3k">
        Ve trojkovém Python'u už je chování očekávané:
    </p>
    <example lang="python">
        >>> [x for x in range(5)]
        [0, 1, 2, 3, 4]
        >>> x
        Traceback (most recent call last):
          File "&lt;stdin>", line 1, in &lt;module>
        NameError: name 'x' is not defined
    </example>

</slide>
<slide title="„print()“ vs „print“">

    <p>
        Je to pouze o jeden znak víc, ale všichni na tuto změnu nadávají – z <em>print</em>u se ve trojkovém Python'u stala místo dřívějšího příkazu funkce. Drobnějších změn za tím schovaných je více, ale ty nejviditelnější jsou asi:
    </p>
    <table border="1" class="center">
        <tr>
            <th>3.x</th>
            <th>2.x</th>
        </tr>
        <tr>
            <td>
                <example lang="python">
                    print(x, end='')
                </example>
            </td>
            <td>
                <example lang="python">
                    print x,
                </example>
            </td>
        </tr>
        <tr>
            <td>
                <example lang="python">
                    print("Chyba!", file=sys.stderr)
                </example>
            </td>
            <td>
                <example lang="python">
                    print >>sys.stderr, "Chyba!"
                </example>
            </td>
        </tr>
        <tr>
            <td>
                <example lang="python">
                    print( (x, y) )
                </example>
            </td>
            <td>
                <example lang="python">
                    print (x, y)
                </example>
            </td>
        </tr>
    </table>
    <p>
        Obecně je „trojkový“ <em>print()</em> konzistentnější a díky <a href="/materialy/python/cmd/print.xml">armádě pojmenovaných parametrů</a> nakonec i mocnější. Nehledě na to že ho jako funkci můžete snadno úplně předefinovat, což s příkazem pochopitelně nešlo.
    </p>

</slide>
<slide title="Krajně nebezpečný „input()“">

    <p>
        Zkuste uhodnout, co bude v proměnné <code>xs</code>, když následujícímu programu zadáte na vstupu řetězec <em>os.getcwd()</em>:
    </p>
    <example lang="python">
        import os
        xs = input('Vstup: ')
    </example>
    <p class="py3k">
        Ve trojkovém Python'u pěkně spořádaně zadaný řetězec <code>'os.getcwd()'</code>.
    </p>
    <example lang="python">
        >>> import os
        >>> xs = input('Vstup: ')
        Vstup: os.getcwd()
        >>> xs
        'os.getcwd()'
    </example>
    <p class="py2k">
        Ovšem v Python'u dvojkovém to snad radši ani nechcete vědět:
    </p>
    <example lang="python">
        >>> import os
        >>> xs = input('Vstup: ')
        Vstup: os.getcwd()
        >>> xs
        'C:\\PROFILES\\pirat'
    </example>
    <p>
        Ano, je to tak – <strong>dvojkový Python automaticky volá na vstup funkce <em>input()</em> extrémně nebezpečnou funkci <em>eval()</em></strong>!!! Radši si ani nezkoušet představit, co všechno se tímhle dá způsobit… Vstup bez vyhodnocení vrací ve dvojkové řadě funkce <code>raw_input()</code>, která se chová obdobně jako trojkový <em>input()</em>.
    </p>

</slide>
<slide title="„repr()“ vs „``“">

    <p class="py3k">
        Zatímco v trojkovém Python'u se tisknutelná reprezentace objektů dostane zásadně pomocí funkce <em>repr()</em>..
    </p>
    <example lang="python">
        >>> repr(int)
        "&lt;class 'int'>"
    </example>

    <p class="py2k">
        ..v Python'u dvojkovém je kromě ní k dispozici i varianta se zpětnými apostrofy <em>``</em> (tzv. <em>backticks</em>):
    </p>
    <example lang="python">
        >>> `int`
        "&lt;type 'int'>"
        >>> repr(int)
        "&lt;type 'int'>"
    </example>

</slide>
<slide title="Výjimky – „except“">

    <p class="py3k">
        Ve trojkovém Python'u se objekt výjimky pro zpracování odchytává logickým a průhledným způsobem pomocí klíčového slova <em>as</em>:
    </p>
    <example lang="python">
        try:
            ...
        except Výjimka as v:
            ...
    </example>
    <p>
        Přitom chcete-li odchytit vícero výjimek ve stejné větvi, oddělíte je čárkami:
    </p>
    <example lang="python">
        try:
            ...
        except Výjimka1, Výjimka2, ...:
            ...
    </example>

    <p class="py2k">
        Pro zmatení nepřítele používá Python dvojkový obyčejnou čárku, ačkoliv nejde o žádnou zjevnou dvojici, ovšem pro odchycení objektu výjimky:
    </p>
    <example lang="python">
        try:
            ...
        except Výjimka, v:
            ...
    </example>
    <p>
        Vícero typů výjimek najednou pak naprosto nelogicky bere pouze jako explicitně závorkami vyznačenou n-tici:
    </p>
    <example lang="python">
        try:
            ...
        except (Výjimka1, Výjimka2, ...):
            ...
    </example>

</slide>
<slide title="Výjimky – „raise“">

    <p class="py2k">
        Podobného „napřímení“ doznalo i vyvolání/přeposlání výjimky pomocí <em>raise</em> s dodaným parametrem, které se ve dvojkovém Python'u dalo zapsat dvěma způsoby:
    </p>
    <example lang="python">
        raise Výjimka, parametr
            ↔
        raise Výjimka(parametr)
    </example>

    <p class="py3k">
        Dnes je možný již pouze druhý způsob:
    </p>
    <example lang="python">
        raise Výjimka(parametr)
    </example>
    <p>
        PS: S výjimkami je to tedy poněkud zamotanější, protože ve dvojce existuje i varianta s trojicí, kde posledním prvkem je <em>traceback</em>. Ten se ve trojce předává magickým parametrem <em>__traceback__</em>, což sice poněkud protáhlo kód, ale podle mého většinové použití výjimek se stalo výrazně čitelnějším. Pro podrobnosti viz <a href="https://www.python.org/dev/peps/pep-3109/" class="external">PEP 3109</a>.
    </p>

</slide>
<slide title="Použití metatříd">

    <p class="py3k">
        Zatímco v trojkovém Python'u zavedete konkrétní metatřídu u třídy pomocí pojmenovaného parametru..
    </p>
    <example lang="python">
        class MojeTřída(metaclass=M):
            ...
    </example>

    <p class="py2k">
        ..ve dvojkovém to byl/je magický parametr v těle třídy:
    </p>
    <example lang="python">
        class MojeTřída:
            __metaclass__ = M
            ...
    </example>

</slide>
<slide title="„super()“">

    <p class="py3k">
        Zavolat metodu rodičovské třídy je ve trojkovém Python'u naštěstí už směšně jednoduché..
    </p>
    <example lang="python">
        class Školák(Člověk):
           
          def __init__(self, *args):
              super().__init__(args)
              ...
    </example>

    <p class="py2k">
        ..protože v Python'u dvojkovém se musela funkce <em>super()</em> volat s explicitními parametry:
    </p>
    <example lang="python">
        class Školák(Člověk):
           
          def __init__(self, *args):
              super(Školák, self).__init__(args)
              ...
    </example>

</slide>
<slide title="">

    <p class="py3k">
    </p>
    <example lang="python">
    </example>

    <p class="py2k">
    </p>
    <example lang="python">
    </example>

</slide>
<!--
<slide title="">

    <p class="py3k">
    </p>
    <example lang="python">
    </example>

    <p class="py2k">
    </p>
    <example lang="python">
    </example>

</slide>
-->


</lecture>
