Kromě konstrukce while, kterou jsme si představili v minulé kapitole, zná Python i další příkazy pro řízení toku programu podobné příkazům v jiných programovacích jazycích.
Pravděpodobně nejznámějším a nejjednodušším typem příkazu pro řízení toku programu je konstukce if. Například:
>>> x = int(raw_input("Zadejte celé číslo: ")) >>> if x < 0: ... x = 0 ... print 'Záporné číslo změněno na nulu' ... elif x == 0: ... print 'Nula' ... elif x == 1: ... print 'Jedna' ... else: ... print 'Více' ...
Konstukce if může mít volitelně několik větví elif a jednu větev else. Klíčové slovo "elif" je zkratkou pro "else if", čímž se jazyk vyhýbá přílišnému odsazení při použití opravdu rozsáhlých konstrukcí if s mnoha větvemi else, které obsahují další konstrukce if. Konstukce if ... elif ... elif ... je náhradou příkazů switch nebo case tak, jak je známe z ostatních jazyků.
Konstrukce for se trochu odlišuje od konstrukce for, jak jí známe z jazyků C nebo Pascal. Jazyk Pascal nabízí iterování pouze po prvcích aritmetické posloupnosti, jazyk C nabízí možnost řídit toto iterování a poskytuje také podmínku pro ukončení cyklu. V jazyce Python cyklus for iteruje přes prvky libovolné sekvence (třeba seznamu nebo řetězce) v pořadí, v jakém se vyskytují v sekvenci. Například:
>>> # Vytisknutí délky řetězců: ... a = ['kočka', 'okno', 'defenestrace'] >>> for x in a: ... print x, len(x) ... kočka 5 okono 4 defenestrace 12
Není bezpečné modifikovat sekvenci, jejímiž prvky se v cyklu iteruje (to platí samozřejmě pouze pro proměnné sekvenční typy, např. seznamy, neměnné sekvenční typy, jako třeba tuple, nemůžeme už z principu měnit). Potřebujete-li změnit seznam, přes nějž se iteruje (například chcete zdvojit vybrané položky), musíte iterovat prvky kopie původního seznamu. Nejschůdnějším řešením je vytvoření kopie slice konstrukcí:
>>> for x in a[:]: # vytvoření kopie celého seznamu ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrace', 'kočka', 'okno', 'defenestrace']
Potřebujete-li iterovat přes sekvenci čísel, může vám přijít vhod interní funkce range(). Ta vytváří seznam obsahující aritmetickou posloupnost:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Předaná konečná hodnota nikdy není částí vygenerovaného seznamu,
range(10)
vrátí seznam 10 hodnot. Je rovněž možné začít posloupnost
jiným číslem než nulou, případně můžete zvolit i jiný přírůstek než jedna
(včetně záporných čísel):
>>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70]
Pro průchod indexy nějaké sekvence, je vhodné zkombinovat funkce range() a len() jako v následující ukázce:
>>> a = ['Micinko', 'Lízinko', 'čičí', 'vylezte'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Micinko 1 Lízinko 2 čičí 3 vylezte
Příkaz break, stejně jako v C, ukončí aktuální for nebo while cyklus.
Příkaz continue, také vypůjčený z C, způsobí pokračování další iterací aktuálního cyklu.
Konstrukce cyklů mohou také mít klauzuli else
, ta je spuštěna když
cyklus skončí díky vyčerpání všech prvků sekvence (cyklus for) nebo
když se řídící podmínka stane nepravdivou (cyklus while), ale nikdy
ne, když je cyklus ukončen příkazem break. Toto ukazuje následující
cyklus zaměřený na vyhledávání prvočísel:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'je rovno', x, '*', n/x ... break ... else: ... # cyklus proběhl bez nalezení dělitele ... print n, 'je prvočíslo' ... 2 je prvočíslo 3 je prvocíslo 4 je rovno 2 * 2 5 je prvočíslo 6 je rovno 2 * 3 7 je prvočíslo 8 je rovno 2 * 4 9 je rovno 3 * 3
Příkaz pass je prázdný příkaz. Může být použit na místech, kde je syntakticky požadován nějaký příkaz, ale program žádnou akci nevyžaduje. Například:
>>> while 1: ... pass # činné čekaní na přerušení ...
Kromě funkcí definovaných jazykem Python si můžeme napsat i vlastní funkce, tzv. uživatelsky definované funkce. Můžeme například vytvořit funkci, která vytiskne Fibonacciho rozvoj do zadané meze:
>>> def fib(n): # vypiš Fibonacci rozvoj do n ... """Vytiskne Fibonacciho rozvoj do n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Nyní zavoláme funkci tak, jak jsme si ji definovali: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Klíčové slovo def uvozuje definici funkce. Musí být následováno jménem funkce a uzávorkovaným výčtem formálních argumentů. Příkazy, které tvoří tělo funkce, následují na další řádce a musí být odsazeny. Prvním příkazem těla funkce může volitelně být řetězec, tento řetězec je pak tzv. dokumentačním řetězcem (anglicky docstring. ).
Existují nástroje, které používají dokumentační řetězce k automatickému generování dokumentace nebo které umožňují uživateli interaktivně procházet kódem programu, přičemž zobrazují právě tyto dokumentační řetězce. Je proto dobrým zvykem psát dokumentační řetězce ke každé funkci, kterou napíšete. Dokumentační řetězce může kromě funkce mít i třída, metoda nebo třeba modul.
Spuštěním funkce se vytvoří nový prostor jmen používaný pro lokální proměnné této funkce. Konkrétněji -- všechna přiřazení ve funkci ukládají hodnoty do lokálního prostoru jmen, jestliže při odkazování se na proměnnou tato není nalezena v lokálním oboru jmen, interpretr nahlédne nejprve do globálního oboru jmen a nakonec do oboru jmen interních. Díky tomu nemůžete přiřadit uvnitř nějaké funkce hodnotu přímo globální proměnné (lze to až po té, co jí deklarujeme jako globální příkazem global), odkazovat se na ní ale můžeme.
Skutečné argumenty (parametry) předané při zavolání funkce jsou uloženy v lokálním prostoru jmen volané funkce, tudíž argumenty jsou předávany hodnotou (kde slovo hodnota vždy znamená odkaz na objekt, ne přímo hodnotu objektu).4.1 Jestliže funkce zavolá jinou funkci, je opět pro toto volání vytvořen nový prostor jmen.
Definování funkce vytvoří novou proměnnou -- jméno funkce v aktuálním prostoru jmen. Její hodnota má speciální typ -- uživatelsky definovaná funkce. Tato hondota může být přiřazena jiné proměnné, které poté může být použita také jako funkce. Takto můžeme libovolný objekt přejmenovat:
>>> fib <function object at 10042ed0> >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89
Můžete namítnout, že funkce fib
není funkce, ale procedura. Python,
podobně jako C, považuje procedury za speciální druh funkce, která nevrací
žádnou hodnotu. Ve skutečnosti procedury v Pythonu také vrací hodnotu. Tato
hodnota je jmenuje None
a je to interní proměnná. Vypsání její hodnoty
je ale potlačeno interpretrem. Jestliže jej opravdu chcete vidět,
musíte si o to říci:
>>> print fib(0) None
Je jednoduché napsat funkci, která, místo aby vytiskla výsledek, vrátí seznam čísel Fibonacciho rozvoje:
>>> def fib2(n): # vrátí Fibonacciho rozvoj do čísla n ... """Vrátí seznam obsahující Fibonacciho rozvoj do čísla n.""" ... vysledek = [] ... a, b = 0, 1 ... while b < n: ... vysledek.append(b) # viz níže ... a, b = b, a+b ... return vysledek ... >>> f100 = fib2(100) # zavoláme funkci fib2() >>> f100 # a vytiskneme její výsledek [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Tento příklad ukazuje další pro nás nové vlastnosti jazyka Python:
None
, stejně jako vykonání celého
těla funkce rovněž.
vysledek.append(b)
zavolá metodu seznamu vysledek
.
Metoda je funkce, která "patří" k určitému objektu a používáme jí za pomoci
syntaxe obj.jméno_metody
, kde obj
je nějaký objekt (popřípadě i
výraz, jehož výsledek je objekt) a jméno_metody
je jméno metody, které
je definováno typem objektu. Různé typy definují různé metody. Metody různých
typů mohou mít stejná jména, aniž by došlo ke dvojzačnostem (je rovněž možné
definovat vlastní typy objektů a vlastní metody za použití tříd, jak se
naučíme později). Metoda append() použitá v tomto příkladě, je
definována pro seznamy, přidá nobý prvek na konec seznamu. V tomto případě
odpovídá výrazu "vysledek = vysledek + [b]", ale je efektivnější.
Je také možné definovat funkci s množstvím různých argumentů. Python nabízí i tři speciální tvary, které mohou být libovolně kombinovány.
Velice užitečná je možnost specifikovat implicitní hodnotu jednoho nebo více argumentů. Takto se vytvoří funkce, které může být volána s méně argumenty, než s kolika byla definována
def ano_ne(vyzva, opakovani=4, upozorneni='Ano nebo ne, prosím'): while 1: ok = raw_input(vyzva) if ok in ('a', 'an', 'ano'): return 1 if ok in ('n', 'ne'): return 0 opakovani = opakovani - 1 if opakovani < 0: raise IOError, 'uživatel ignorant' print upozorneni
Tato funkce může být volána jako
ano_ne('Chcete opravdu ukončit program?')
nebo jako
ano_ne('Přejete si prepsat soubor?' 2)
.
Implicitné hodnoty jsou vyhodnoceny v místě definice funkce a v definujícím prostoru jmen, takže
i = 5 def f(arg=i): print arg i = 6 f()
vytiskne 5
.
Důležité upozornění: Implicitní hodoty argumentů jsou vyhodnoceny pouze jednou. Toho můžeme s výhodou využít, je-li implicitní hodnotou proměnný objekt jako třeba seznam. Například, následující funkce shromažďuje argumenty předané jednotlivým voláním:
def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3)
Tento příklad vytiskne:
[1] [1, 2] [1, 2, 3]
Jestliže si nepřejete sdílení hodnot mezi jednotlivými voláními, můžete funkci napsat třeba takto:
def f(a, L=None): if L is None: L = [] L.append(a) return L
Funkce může také být volána za použití keyword argumentů v následujícím tvaru: "keyword = hodnota". Třeba následující funkce
def papousek(napeti, xxx='Python', akce='zpívat', keczy='bla, bla, bla'): print "-- Tento papoušek nebude", akce, print "když do něj pustíte", napeti, "Voltů." print "-- A nějaké kecy:", keczy print "-- A ještě něco:", xxx, "!"
může být volána následujícími způsoby:
papousek(1000) papousek(akce = 'řvát', napeti = 1000000) papousek('tisíc', xxx = 'Chudák papouch') papousek('milion', 'Papoušek to nerozchodí', 'skákat')
ale následující volání jsou chybná:
papousek() # chybějící povinný argument papousek(napeti=5.0, 'ahoj') # povinný argument následující po keyword papousek(110, napeti=220) # hodnota argumentu předána dvakrát papousek(vrah='Miroslav Sládek') # neznámý keyword argument
Obecně - seznam argumentů musí mít všechny povinné (poziční) argumenty uvedeny před keyword argumenty a jména keyword argumentů musí odpovídat jménům formálních argumentů, přičemž není rozhodující, jestli formální argument má implicitní hodnotu nebo ne. Žádnému argumentu však nesmí být předána hodnota více jak jednou -- jméno formálního argumentu odpovídající pozičnímu argumentu nemůže být použito jako keyword argument v tomtéž volání funkce, tuto chybu názorně ukazuje následující příklad:
>>> def funkce(a): ... pass ... >>> funkce(0, a=0) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: keyword parameter redefined
Jestliže je poslední formální argument zapsán ve tvaru **jméno
,
pak je mu přiřazeno asociativní pole těch keyword argumentů, jejichž jména
neodpovídají formálním parametrům. Navíc může být tento tvar zkombinován s
formálním argumentem ve tvaru *jméno
(popsaným v další podsekci),
kterému jsou přiřazeny všechny přebývající poziční argumenty
(*jméno
musí bt uveden před **jméno
). Jestliže
definujeme funkci podobně jako:
def big_burger(druh, *argumenty, **keyword): print "-- Máte", druh, '?' print "-- Promiňte,", druh, "došly." for arg in argumenty: print arg print '-'*40 for kw in keyword.keys(): print kw, ':', keyword[kw]
Pak může být volána jako:
big_burger('cheesburgery', "Velice se omlouvám, pane.", "Opravdu se velice se omlouvám, pane.", zakaznik='Adam', prodavac='Bedřich', obchod='Honzův domáci BigBurger')
Přičemž vytiskne:
-- Máte cheesburgery ? -- Promiňte, cheesburgery došly. Velice se omlouvám, pane. Opravdu se velice se omlouvám, pane. ---------------------------------------- obchod : Honzův domáci BigBurger prodavac : Bedřich zakaznik : Adam
Konečně, poslední často používanou vlastností jazyka Python je možnost
specifikovat, že funkce může být volána s libovolným množstvím argumentů. Tyto
argumenty budou převedeny na tuple a předány pomocí speciálního formálního
argumentu *arg
:
def fprintf(soubor, format, *argumenty): file.write(format % argumenty)
Na požadavek programátorů bylo do jazyka Python přidáno pár nástrojů obdobných těm z funkčních programovacích jazyků. Za pomoci klíčového slova lambda můžeme vytvořit malou anonymní funkci. Takto například vypadá funkce, která vrací součet jejích dvou argumentů: "lambda a, b: a+b". Lambda funkce mohou být použity kdekoli, kde je požadován funkční objekt. Tělo lambda funkcí je omezeno na jediný výraz. Semanticky jsou lambda funkce jiným vyjádřením definice funkce. Podobně jako definice vložených funkcí, labmda funkce se mohou odkazovat na proměnné z vnější funkce:
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43
Existují určité konvence, jak psát obsah a jak formátovat dokumentační řetězce.
První řádka by měla vždy být krátká, měla by shrnovat účel objektu. Pro krátkost by neměla explicitně pojmenovávat objekt (s výjimkou sloves popisujících určitou činnost), protože jméno objektu je dostupné jinou cestou. Tato řádka by měla začínat velkým písmenem a končit tečkou.
Jestliže dokumentační řetězec má více řádků, druhá řádka by měla být prázdá a měla by vizuálně oddělovat souhrn od zbytku popisu. Následující řádky mohou obsahovat jeden nebo více odstavců popisující volací konvence objektu, jeho vedlejší efekty apod.
Parser interpretru neodstraňuje odsazení z víceřádkových řetězců, takže nástroje, které generují dokumentaci, by měly toto odsazení odstranit, pokud je to žádoucí. To umožní následující konvence. První neprázdná rádka po první řádce řetězce určuje velikost odsazení pro celý dokument. Odpovídající počet mezer je poté odstraněn ze začátku každého rádku. Řádky, které jsou odsazeny méně, budou zkráceny o všechny bílé znaky na začátku. Odsazení by mělo být testováno až po náhradě tabulátoru za 8 mezer.
Zde je příklad víceřádkového dokumentačního řetězce:
>>> def moje_funkce(): ... """Nic nedělá, ale zdokumentujeme ji. ... ... Nedělá opravdu nic. ... """ ... pass ... >>> print moje_funkce.__doc__ Nic nedělá, ale zdokumentujeme ji. Nedělá opravdu nic.