Subsections

 
3. Úvod do jazyka Python

Ve všech příkladech v této knize, které uvádějí ukázky vzorového sezení je vstup pro interpretr označen uvedením výzvy (primární ">>" a sekundární "... "). Výstup z programu je uváděn na samotném řádku přesně tak, jak jej příkaz print vytiskl. Sekundární výzva uvedená na samostatném řádku znamená prázdný řádek a je použita k ukončení víceřádkového příkazu.

Mnoho příkladů v této publikaci, přestože jsou určeny pro zápis v interaktivním módu, obsahuje komentáře. Každý komentář v jazyce Python začíná znakem křížek "#" a pokračuje do konce fyzického řádku. Komentář se může objevit jak na začátku řádky, tak může následovat po "bílých znacích" 3.1 nebo kódu. Znak "#" uvedený uvnitř řetězce neznamená komentář, je považován za znak řetězce:

# toto je první komentář
SPAM = 1                 # a toto je druhý komentář
                         # ... a nyní třetí!
STRING = '# Toto není komentář.'

 
3.1 Python jako kalkulátor

Nyní si vyzkoušíme několik jednoduchých příkazů jazyka Python. Spusťte si interpretr a počkejte na zobrazení primární výzvy ">>".

 
3.1.1 Čísla

Interpretr se chová jako jednoduchý kalkulátor. Můžete zapsat libovolný výraz a on vypíše jeho hodnotu. Zápis výrazů je jednoduchý: operátory +, -, * a / fungují stejně jako v jiných jazycích (například Pascal nebo C), rovněž můžete používat závorky pro změnu priority výrazů. Například:

>>> 2+2
4
>>> # Toto je komentář
... 2+2
4
>>> 2+2  # a toto je komentář na stejném řádku jako kód
4
>>> (50-5*6)/4
5
>>> # Dělení celých čísel vrátí celé číslo:
... 7/3
2
>>> 7/-3
-3

Stejně jako v C je znak rovnítko ("=") určen pro přiřazení hodnoty proměnné. Hodnota proměnné po přiřazení již není interaktivním interpretrem vypsána:

>>> vyska = 20
>>> sirka = 5*9
>>> vyska * sirka
900

Hodnota může být přiřazena i více proměnným najednou:

>>> x = y = z = 0  # Vynuluj x, y a z
>>> x
0
>>> y
0
>>> z
0

Python plně podporuje operace v plovoucí řádové čárce (tj. desetinná čísla). Operátor pracující s různými typy operandů si nejprve zkonvertuje celá čísla na čísla v plovoucí řádové čárce a následně provede výpočet (obdobné chování možná znáte z jazyka C):

>>> 3 * 3.75 / 1.5
7.5
>>> 7.0 / 2
3.5

Python také plně podporuje komplexní čísla, přičemž imaginární číslo je zapisováno s příponou "j" nebo "J". Komplexní čísla zapisujeme ve tvaru "(Re + Imj)" nebo je můžeme vytvořit pomocí interní funkce "complex(Re, Im)":

>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)

Komplexní čísla jsou vždy reprezentována dvojicí desetinných čísel, reálnou a imaginární částí. Chceme-li získat velikosti těchto částí čísla z, použijeme zápisu z.real a z.imag:

>>> z=1.5+0.5j
>>> z.real
1.5
>>> z.imag
0.5

Poněvadž v matematice neexistuje způsob, jak převést komplexní číslo na reální, ani Python nedovoluje použití konverzních funkcí float(), int() a long() s komplexním argumentem. Raději použijte funkci abs(z) pro získání absolutní hodnoty komplexního čísla, nebo zápis z.real reprezentují reálnou část čísla:

>>> a=3.0+4.0j
>>> float(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: can't convert complex to float; use e.g. abs(z)
>>> a.real
3.0
>>> a.imag
4.0
>>> abs(a)  # sqrt(a.real**2 + a.imag**2)
5.0
>>>

Pokud používáte Python jako stolní kalkulátor, pak se můžete velice snadno vrátit k předchozímu výsledku -- ten reprezentuje proměnná _, například:

>>> urok = 12.5 / 100
>>> penize = 100.50
>>> penize * urok
12.5625
>>> penize + _
113.0625
>>> round(_, 2)
113.06
>>>

Hodnota proměnné _ by nikdy neměla být modifikována uživatelem. Pokud byste jí přiřadili hodnotu, vytvořili byste nezávislou lokální proměnnou se stejným jménem, která by zakryla interní proměnnou s tímto chováním.

 
3.1.2 Řetězce

Podobně jako s čísly můžete v Python pracovat i s řetězci. Ty mohou být zapsány mnoha způsoby, především je možné je uvodit jak jednoduchými, tak i dvojitými uvozovkami:

>>> 'houby s voctem'
'houby s voctem'
>>> 'rock\'n\'roll'
"rock'n'roll"
>>> "rock'n'roll"
"rock'n'roll"
>>> '"To je vražda," napsala.'
'"To je vražda," napsala.'
>>> "\"To je vražda,\" napsala."
'"To je vražda," napsala.'
>>> '"To je rock\'n\'roll," řekla.'
'"To je rock\'n\'roll," řekla.'

Mnohdy programátor potřebuje řetězec, který je rozložen přes více řádků. Dosáhnout toho opět můžeme několika způsoby. První z nich, který se neváže pouze na řetězce, je spojení dvou po sobě jdoucích řádků znakem zpětného lomítka:

hello = 'Toto je dlouhý řetězec obsahující mnoho\n\
řádek textu, stejně jej zapisujete i v C.\n\
    "Bílé" znaky na začátku řádku se samozřejmě\
 berou v úvahu.'

print hello

Nevýhodou tohoto přístupu je nutnost všechny řádky ukončit vložením znaků \n. Zpětné lomítko způsobí ignorování následujícího znaku nového řádku, řetězec tak může pokračovat na dalším řádku, aniž by bylo nutné ho ukončit uvozovkami. To demonstruje předchozí příklad, jehož výstupem je tento text:

Toto je dlouhý řetězec obsahující mnoho
řádek textu, stejně jej zapisujete i v C.
    "Bílé" znaky na začátku řádku se samozřejmě berou v úvahu.

Python podporuje i tzv. raw řetězce (cosi jak ryzí, syrové řetězce), u nichž se řídící (escape) sekvence nepřevádí na odpovídající znaky.3.2. Raw řetězce charakterizuje předpona r. Potom řetězec r'\n' odpovídá dvěma znakům - zpětnému lomítku a znaku n, kdežto řetězec '\n' je jediný znak nového řádku:

hello = r'Toto je dlouhý řetězec obsahující mnoho\n\
řádek textu, stejně jej zapisujete i v C.'

print hello

Tento příklad vytiskne text:

Toto je dlouhý řetězec obsahující mnoho\n\
řádek textu, stejně jej zapisujete i v C.

Další možností, jak vytvořit víceřádkový řetězec je jeho uzavření mezi odpovídající pár trojitých uvozovek (""" nebo '''). To má tu výhodu, že nemusíme explicitně zapisovat konce řádků, ty bude řetězec obsahovat přesně tak, jak jsou zapsány ve zdrojovém kódu:

print """
Použití: nakladač [VOLBY] 
     -h                        Zobraz tuto zprávu
     -H hostname               Připoj se na tento počítač
"""

Tato ukázka vytiskne následující výstup:

Použití: nakladač [VOLBY]
     -h                        Zobraz tuto zprávu
     -H hostname               Připoj se na tento počítač

Abychom věděli přesnou podobu řetězce, vytiskne jej interpretr stejným způsobem jako jej zapisujeme, přičemž i všechny speciální znaky jsou uvozeny zpětným lomítkem. (Pokud chceme zobrazit "hodnotu" řetězce, tj. to, co skutečně obsahuje, můžeme použít příkaz print popsaný později. Ten řetězec vytiskne bez uvozovek a se všemi speciálními znaky.)

Řetězce můžeme spojovat pomocí operátoru +, dokonce je lze opakovat operátorem *:

>>> slovo = 'Help' + 'A'
>>> slovo
'HelpA'
>>> '<' + slovo*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'

Nalezne-li interpretr v kódu dva zápisy řetězců bezprostředně za sebou, spojí je dohromady jako by mezi nimi ležel operátor +. První řádek příkladu mohl být tedy zapsán jako slovo = 'Help' 'A'. Ale pozor, takto lze spojovat pouze zápisy řetězců, pro spojení řetězce a výrazu musíme použít operátor +!

>>> import string
>>> 'str' 'ing'                   #  <-  Správně
'string'
>>> string.strip('str') + 'ing'   #  <-  Správně
'string'
>>> string.strip('str') 'ing'     #  <-  CHYBNĚ!!!
  File "<stdin>", line 1, in ?
    string.strip('str') 'ing'
                            ^
SyntaxError: invalid syntax

Řetězce můžeme (podobně jako v jazyce C) indexovat. První znak řetězce pak má index 0. Poněvadž je Python velice uživatelsky přítulný, nekomplikuje život programátora speciálním typem určeným pro jediný znak -- každý znak řetězce je opět řetězec s délkou 1. Na získání podřetězce nepotřebujeme žádné speciální funkce, samotný jazyk (podobně jako jazyk Icon) podporuje indexování subsekvencí3.3. Subsekvenci indexujeme podobně jako jednotlivé znaky, pouze potřebuje dva indexy (začátek a konec subsekvence), které oddělíme dvojtečkou:

>>> slovo[4]
'A'
>>> slovo[0:2]
'He'
>>> slovo[2:4]
'lp'

Mezi řetězci v C a v Pythonu ale existuje obrovský rozdíl. Řetězce v jazyce Python nelze měnit. Jde o celkem logický závěr, řetězec 'ahoj' vždy bude řetězec 'ahoj', proč bychom ho tedy měli měnit?3.4. Pokusíme-li se změnit určitou pozici v řetězci, dojde k chybě:

>>> slovo[0] = 'x'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
>>> slovo[:1] = 'Splat'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: object doesn't support slice assignment

Proto jedinou cestou, jak vytvářet nové řetězce, je jejich kombinování, které je velice jednoduché a přitom efektivní:

>>> 'x' + slovo[1:]
'xelpA'
>>> 'Splat' + slovo[4]
'SplatA'

Slice indexy mají ještě další specifické vlastnosti. Vynecháme-li první index, je za něj automaticky dosazena nula (začátek řetězce). Při neuvedení druhého indexu se použije délka řetězce (čili konec řetězce): 3.5.

>>> slovo[:2]    # První dva znaky
'He'
>>> slovo[2:]    # Vše s výjimkou prvních dvou znaků
'lpA'

Kód ve tvaru s[:i] + s[i:] je samozřejmě vyhodnocen jako s:

>>> slovo[:2] + slovo[2:]
'HelpA'
>>> slovo[:3] + slovo[3:]
'HelpA'

Další vlastností slice indexů je jejich automatické "zarovnávání" na rozměr řetězce. Je-li totiž index použitý ve slice konstrukci příliš velký, je nahrazen délkou řetězce. Podobně -- pokud je dolní index větší než horní, je výsledkem prázdný řetězec:

>>> slovo[1:100]
'elpA'
>>> slovo[10:]
''
>>> slovo[2:1]
''

Pokud jsou indexy záporná čísla, dojde k počítání od konce řetězce. Názorně to ukazuje následující příklad i s komentáři:

>>> slovo[-1]     # Poslední znak
'A'
>>> slovo[-2]     # Předposlední znak
'p'
>>> slovo[-2:]    # Poslední dva znaky
'pA'
>>> slovo[:-2]    # Vše kromě posledních dvou znaků
'Hel'

Pozor ale, -0 je totéž co 0, k žádnému indexování od konce řetězce tím pádem nedojde:

>>> slovo[-0]     # (-0 je totéž co 0)
'H'

Záporné indexy při indexaci podřetězců jsou zarovnány na velikost řetězce, proto není chybou, sahají-li indexy mimo řetězec. To platí ale pouze pro slice indexy, indexy, které vystupují samostatně jsou ponechány tak, jak jsou. Pokud je řetězec kratší a index padne mimo něj, dojde k chybě:

>>> slovo[-100:]
'HelpA'
>>> slovo[-10]    # CHYBNĚ!!!
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: string index out of range

Pokud i přesto, že jsme se podsekvencím tolik věnovali, nechápete, jak jednotlivé znaky a podsekvence z nich složené získat, možná vám přijde vhod následující schema.

Důležité je si zapamatovat, že slice indexy ukazují mezi znaky, přičemž levá hrana prvního znaku má číslo 0 a pravá hrana posledního znaku řetězce o n znacích má index n:

 +---+---+---+---+---+ 
 | H | e | l | p | A |
 +---+---+---+---+---+ 
 0   1   2   3   4   5 
-5  -4  -3  -2  -1

Na prvním řádku jsou uvedeny všechny možné slice-indexy 0...5 v řetězci 'HelpA', na druhém pak odpovídající záporné hodnoty. Řez od i do j je tedy tvořen všemi znaky mezi hranami označenými mezi hranami označenými i a j.

Pokud potřebujete zjistit délku určitého řetězce, jistě využijete interní funkci len():

>>> s = 'supercalifragilisticexpialidociální'
>>> len(s)
35

Pro nezáporné slice-indexy je délka řezu rozdílem slice-indexů pokud oba "padnou" dovnitř řetězce. Například, délka řezu word[1:3] je 2.

 
3.1.3 Řetězce Unicode

Vydáním Pythonu 2.0 se jazyk dostal mezi skupinku jazyků podporujících Unicode. Od té doby Python umí pracovat s Unicode řetězci (viz http://www.unicode.org/) úplně stejným způsobem jako s obyčejnými řetězci. To umožňuje snadnou integraci Unicode do již existujících aplikací. Dokonce je možné díky konverzním funkcím snadno převádět obyčejné řetězce na Unicode a zpět.

Čím je Unicode tak pokrokové? Především v tom, že každému znaku libovolného jazyka přiřazuje jedinečný index. Tím se liší od dříve používaného schematu, kdy se používalo pouze 256 indexů a několik kódových tabulek, takže jednomu indexu odpovídalo více znaků (každý v jiné tabulce). To vedlo k velkým zmatkům, rovněž bylo nutné respektovat internacionalizaci3.6 programů, což je zajištění správné funkce programu v různých národních prostředích (program akceptuje národní znaky, správně provádí třídění, konverzi řetězců apod.). Unicode proto definuje pouze jedinou kódovou stránku pro všechny jazyky. Program pak zachází se všemi znaky Unicode stejným způsobem a nepotřebuje rozlišovat mezi různými jazyky a kódovými stránkami.

Unicode řetězce můžeme zapisovat přímo ve zdrojovém kódu programu. Pouze před samotný řetězec vložíme prefix u (podobně jako u raw řetězců prefix r):

>>> u'Hello World !'
u'Hello World !'

Jak vidíme, Unicode řetězec se bez problémů vytvořil. Že se jedná o Unicode řetězec snadno poznáme podle malého písmena "u" před řetězcem. Chcete-li do řetězce vložit speciální znak, můžete tak učinit díky Unicode-Escape módu. Nejlépe to uvidíte na následující ukázce:

>>> u'Hello\u0020World !'
u'Hello World !'

Escape sekvence \u0020 znamená vložení Unicode znaku s hodnotou 0x0020 (znak mezera) na dané místo v řetězci.

Všechny ostatní znaky jsou interpretovány za použití jejich odpovídajících hodnot v kódové stránce Unicode. Jste-li obeznámeni s převodními tabulkami mezi jednotlivými národními kódovými stránkami a kódovou stránkou Unicode, jistě jste si všimli, že prvních 256 znaků Unicode přesně odpovídá všem 256 znakům kódové stránky Latin-1.

I s Unicode řetězci je možné používat raw mód s podobnou funkcí jako raw mód obyčejných řetězců. Tento mód aktivujeme použitím prefixu ur namísto standardního u. Python pak začne používat tzv. Raw-Unicode-Escape mód. V tomto módu Python nahrazuje pouze sekvence typu \uXXXX a ostatní (třeba \n) nechává tak jak jsou:

>>> ur'Hello\u0020World !'
u'Hello World !'
>>> ur'Hello\\u0020World !'
u'Hello\\\\u0020World !'

Výhody raw módu oceníte především potřebujete-li zapsat větší množství zpětných lomítek (např. při zápisu regulérních výrazů).

Nehledě na tyto standardní zápisy nabízí Python ještě celou řadu způsobů, jak Unicode řetězce vytvořit.

Pro konverzi znaků z osmibitového kódování (klasické řetězce) do kódování Unicode můžete použít interní funkci unicode() , která umožňuje přístup ke všem registrovaným kodekům, které dokáží vytvořit Unicode řetězce z řetězce v téměř libovolném kódování (např. Latin-1, ASCII, UTF-8 nebo UTF-16). Implicitní kódování je ASCII. To pro hodnoty znaků používá pouze 7 bitů (proto je možné používat pouze znaky v rozsahu 0 až 127). Při použití rozšířených znaků (např. znaky s diakritikou apod.) dojde k chybě.

Pro převod Unicode řetězce zpět na standardní lze s výhodou použít interní funkci str(). Ta používá implicitní kódování.3.7

>>> u"abc"
u'abc'
>>> str(u"abc")
'abc'
>>> u"äöü"
u'\xe4\xf6\xfc'
>>> str(u"äöü")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)

Chceme-li při konverzi Unicode řetězce na 8bitový specifikovat kódování, v němž má cílový řetězec být, musíme použít metodu encode() Unicodového řetězce. Té předáme jediný argument -- jméno kódování (platí, že všechna jména kódování se píší malými písmeny):

>>> u"äöü".encode('utf-8')
'\xc3\xa4\xc3\xb6\xc3\xbc'

Opačnou konverzi umožňuje již zmíněná funkce unicode(), které lze opět předat jediný argument -- jméno kódování, ve kterém je původní osmibitový řetězec. Převodu výše uvedeného výsledku zpět dosáhneme tímto voláním:

>>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8')
u'\xe4\xf6\xfc'

 
3.1.4 Seznamy

Jazyk Python podporuje i další datové typy. Jde především o tzv. složené datové typy, které slouží k uložení jiných hodnot. Nejuniverzálnější z nich je seznam.

Seznam vznikne, zapíšeme-li výčet libovolných hodnot oddělených čárkou mezi hranaté závorky. Není nutné, aby všechny prvky seznamu měly stejný typ:

>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]

Seznamy podporují, podobně jako řetězce, mnoho dalších operací. Namátkou jmenujme spojování, násobení celým číslem, indexování, operace s podsekvencemi (slice) a další:

>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boe!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!']

Zásadní rozdíl mezi řetězci a seznamy spočívá v možnosti změny prvků. Zatímco u řetězců to nepřipadá v úvahu -- jde o typ neměnný, seznamy se jí nebrání -- tento typ nazýváme proměnný. Seznam lze změnit pomocí přiřazení nového prvku na určitý index:

>>> a
['spam', 'eggs', 100, 1234]
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]

Rovněž lze přiřadit hodnotu určité subsekvenci. Takto dokonce můžeme změnit i počet prvků seznamu:

>>> # Změna prvků:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # Jejich odstranění:
... a[0:2] = []
>>> a
[123, 1234]
>>> # Vložení nových:
... a[1:1] = ['bletch', 'xyzzy']
>>> a
[123, 'bletch', 'xyzzy', 1234]
>>> a[:0] = a     # Vložení kopie seznamu do sebe sama
>>> a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]

Podobně jako na řetězce můžeme i na seznamy aplikovat interní funkci len(). Jako její návratovou hodnotu pak obdržíme počet prvků obsažených v seznamu:

>>> len(a)
8

Někdy se může hodit i možnost vytvořit seznam obsahující jiné seznamy, třeba:

>>> q = [2, 3]
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra')     # Viz. sekce 5.1
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']

V posledním uvedeném příkladě si všimněte jedné věci: objekty p[1] a q jsou jeden a týž seznam. Změnou jednoho se změní i druhý. To umožňuje mechanismus odkazů na objekty. Později se k nim ještě vrátíme, již nyní ale můžeme prozradit, že se jedná o velice důležitou problematiku a bez její znalosti Python těžko pochopíte.

 
3.2 První kroky

Jazyk Python lze samozřejmě použít k daleko komplikovanějším úlohám. Například můžeme vypsat počáteční prvky Fibonacciho rozvoje3.8:

>>> # Fibonacci rozvoj:
... a, b = 0, 1
>>> while b < 10:
...       print b
...       a, b = b, a+b
... 
1
1
2
3
5
8

Tento příklad demonstruje několik pro nás v tuto chvíli nových vlastností:



Footnotes

... znacích"3.1
Tzv. bílé znaky jsou všechny znaky, které reprezentují bílá místa v textu, čili mezery, tabulátory, konce řádků apod.
... znaky.3.2
Escape sekvencí je například \n - znak nového řádku nebo \t - tabulátor
... subsekvencí3.3
V originální dokumentaci slice, v této publikaci budeme někdy používat i výraz slice operace apod.
... měnit?3.4
Obdobně číslo 1 vždy je číslo 1, také se nikdo nezamýšlí nad tím, jestli jde jeho hodnota změnit.
... řetězce):3.5
Ve skutečnosti je druhý index nahrazen velikostí proměnné sys.maxint určující maximální velikost celého čísla na dané platformě.
... internacionalizaci3.6
Anglicky internationalization, často psáno jako "i18n" -- "i" + 18 znaků + "n". Vedle toho existuje i pojem lokalizace, localization ("l10n"), proces překladu původních textů programu do nového jazyka.
... kódování.3.7
Nastavuje se v souboru site.py umístěném v hlavním adresáři běhového prostředí (např. /usr/local/lib). Jeho jméno lze zjistit pomocí funkce sys.getdefaultencoding()
... rozvoje3.8
Fibonacciho rozvoj je určen rovnicí r[n+2] = r[n] + r[n+1]. Začíná tudíž čísly 1, 1, 2, 3, 5, 8, 13 atd.:
... automaticky.3.9
Pro oba nejlepší editory vim a emacs tyto módy samozřejmě existují.
Viz O tomto dokumentu... kde naleznete informace, jak upozornit na případné chyby.