Hlavní navigace

Létající cirkus (9)

Jan Švec

Jak jsem již slíbil na konci minulého dílu našeho seriálu o jazyce Python, budeme se dnes věnovat těm syntaktickým obratům, na které se v minulých dílech nedostalo. Budou to hlavně skládání a rozklad sekvencí, anonymní lambda funkce a formátování řetězců.

Skládání a rozklad sekvencí

Co jsou sekvence, jsme si vysvětlili již v prvních dílech seriálu. Každá sekvence má konečný počet prvků. Proměnnými sekvenčními typy jsou seznamy, neměnnými pak tuple. Ke všemu si programátor může vytvořit vlastní třídy, které implementují rozhraní sekvenčních typů (čtení, nastavení a smazání prvku na určitém indexu). Sekvence jsou indexovány vzestupně čísly (první je podobně jako v C/C++ nula). Seznam vytvoříme pomocí výrazu, který se do češtiny nechá volně přeložit jako konstruktor seznamu (anglicky list display). Jeho nejjednodušší formou je výčet prvků oddělených čárkou a obklopený hranatými závorkami. Další možné formy zápisu si uvedeme později.

Tuple, jak již také víme, vytvoříme jako výčet prvků oddělených čárkou, volitelně uzavřený mezi kulaté závorky. Kulaté závorky můžeme vynechat, používají se v případech, kdy je třeba zabránit dvojznačnostem.

>>> 1, 2, 3
(1, 2, 3)
>>> (1, 2, 3)
(1, 2, 3)
>>> 1, 2, 3,
(1, 2, 3)

Toto vše jsou tuple o třech prvcích 1, 2 a 3. Vytváření tuple pomocí čárek se také nazývá tuple packing (skládání tuple). Opačnou operací je sequence unpacking (rozklad sekvencí). Ta využívá toho, že výčet prvků oddělených čárkou nemusí stát jen na pravé straně přiřazení, ale i na jeho levé straně:

>>> a, b, c = 1, 2, 3
>>> a, b = b, a
>>> a
2
>>> b
1

Toho se dá s výhodou využít pro přiřazení hodnot více proměnným najednou nebo pro záměnu hodnot dvou proměnných bez použití pomocné proměnné. Rozklad sekvencí, jak již napovídá název, se může aplikovat na libovolnou sekvenci. Na pravé straně přiřazení tedy může stát i seznam. Použití rozkladu sekvencí se neomezuje jen na přiřazení, ale s výhodou ho můžeme použít i například při definici funkce nebo ve větvi except konstrukce try..except:

>>> import math                                    # (1)
>>> def vzdalenost_bodu((x1, y1), (x2, y2)):       # (2)
...     return math.sqrt((x1 - x2)**2 + \          # (3)
...                      (y1 - y2)**2)             # (4)
...                                                # (5)
>>> bod1 = (1, 0)                                  # (6)
>>> bod2 = (4, 4)                                  # (7)
>>> print vzdalenost_bodu(bod1, bod2)              # (8)
5.0                                                # (9)

Všimněte si především řádku (2). Funkce vzdalenost_bodu přebírá dva argumenty, které musí být dvouprvkové tuple. Tyto argumenty reprezentují souřadnice x a y dvou bodů. Při volání funkce vzdalenost_bodu s proměnnými bod1 a bod2 jako argumenty dojde právě na řádku (2) k rozkladu těchto tuple na jednoduché proměnné x1, y1, x2 a y2. Je třeba zdůraznit, že výčet prvků na obou stranách přiřazení musí být při aplikování rozkladu sekvencí STEJNÝ. Toto volání funkce vzdalenost_bodu vede k výjimce ValueError:

>>> bod3 = (1, 2, 3)
>>> print vzdalenost_bodu(bod3, bod2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 1, in vzdalenost_bodu
ValueError: unpack tuple of wrong size

Konstuktor seznamu

S konstruktorem seznamu jsme se již setkali. Byla to jeho nejjednodušší varianta, kterou jste poznali ve druhém dílu seriálu:

>>> s1 = [1, 2, 3, 4]                          # (1)
>>> s2 = []                                    # (2)
>>> s3 = [2]                                   # (3)

Jazyk Python ale nabízí i rozšířenou syntax, ve které máme přístupné zjednodušené konstrukce for a if. Jednoduché převedení tuple na seznam by se dalo provést třeba takto:

>>> tuple = (1, 2, 3, 4, 5)
>>> seznam = [i for i in tuple]
>>> seznam
[1, 2, 3, 4, 5]

V tomto případě je jako první v hranatých závorkách uveden výraz, jehož hodnoty budou tvořit prvky nově vzniklého seznamu. Tento konstruktor bere postupně prvky jeden za druhým z proměnné tuple a dosazuje je za řídící proměnnou i. Poté se vyhodnotí výraz před slovem for a z hodnot tohoto výrazu se nakonec složí nový seznam. Pro výpočet tabulky druhých mocnin čísel od 1 do 5 můžeme použít následující výraz:

>>> [i**2 for i in range(1, 6)]
[1, 4, 9, 16, 25]

Konstrukci for lze doplnit i o podmínku, kterou můžeme omezit prvky, jež se mají vyskytnout v novém seznamu. Pro více informací vám doporučuji nahlédout do dokumentace k Pythonu. Seznam sudých čísel od 0 do 10 můžeme vytvořit třeba takto.

>>> [i for i in range(11) if i % 2 == 0]
[0, 2, 4, 6, 8, 10]

Anonymní lambda funkce

Pro definování funkcí zná Python, kromě klíčového slova def, i klíčové slovo lambda, kterým lze vytvořit takzvanou anonymní funkci. Tělem této funkce musí být jediný výraz! Návratová hodnota lambda funkce je rovna hodnotě výrazu. Lambda funkce mohou mít také parametry. Vytvoření nové anonymní funkce je výraz, takže abychom k funkci mohli přistupovat, musíme této funkci přiřadit nějaké proměnné:

>>> to_upper = lambda str: str.upper()
>>> print to_upper('python - batteries included')
PYTHON - BATTERIES INCLUDED

Lambda funkce jsou pouze jakousi zkratkou a její tělo musí opravdu tvořit jediný výraz. Nelze tedy používat konstrukce jako if, for nebo print. Velice se ale hodí jako argument pro funkce, které vyžadují určitou zpětnou vazbu (příkladem mohou být funkce os.path.walk(), map() nebo reduce() – pro jejich popis nahlédněte prozatím do dokumentace, k jejich výkladu se dostaneme v některém z dalších dílů).

Formátování řetězců

Jazyk Python obsahuje operátor %, který normálně znamená zbytek po dělení (modulo). Pro řetezce, a to jak normální, tak Unicode, má tento operátor jiný význam. Jedná se totiž o operátor formátování řetězce, obdoba C funkce sprintf(). Pro formátování řetězců musíme nejprve sestavit formátovací řetězec, v němž pomocí speciálních sekvencí znaků vyznačíme místa, kam se mají vložit data, která se předají operátoru %:

>>> 'Dnes je %s, aktualni cas %d:%02d' % ('patek', 15, 2)
'Dnes je patek, aktualni cas 15:02'

Pro ty, kteří nevědí o čem je řeč, ve zkratce shrnu podstatu formátování řetězců. Ta spočívá v prohledávání formátovacího řetězce (první operand operátoru %) a náhrada každé řídící sekvence jí odpovídajícími daty (druhý operand). Řídící sekvence začíná znakem % a následující znak určuje typ konverze, která se má s odpovídajícím prvkem dat provést (např. %s znamená převedení aktuálního argumentu na řetězec, blíže viz dokumentace k jazyku). Po zpracování řídící sekvence se začne vyhodnocovat další řídící sekvence, spolu s dalším prvkem dat. Jakýkoli řetězec, který nepatří mezi řídící, je do výstupního řetězce zkopírován beze změny. Data jsou operátoru % předávána jako tuple, pouze v případě, kdy se jako data použije jediný výraz, je možné ho psát jako singleton.

Formátovací řetězce umožňují specifikovat i šířku jednotlivých polí, přesnost desetinné části, (ne)zobrazování znaménka + před kladnými čísly, zarovnání nalevo nebo napravo atd. Bližší popis by vystačil na samostatný díl seriálu. Protože jde ale o techniku všeobecně známou (právě z C/C++), nebudeme se jí dále věnovat. Případné zájemce odkáži do dokumentace k jazyku Python (protože tato stránka není uvedena v indexu dokumentace, hledejte v části Python Library Reference sekci číslo 2.2.6.2).

Příště

Další díl bude věnovaný jedné z nových vlastností, které zavádí Python verze 2.2 – iterátory a generátory. Probereme si hlavně syntaxi a funkci klíčového slova yield a zmíníme se o funkci iter() a jejím významu ve spojení s konstrukcí for.

Našli jste v článku chybu?