V této kapitole si zopakujeme a prohloubíme znalosti o datových typech, které můžeme v jazyce Python používat.
Datový typ seznam má kromě již uvedených metod i mnoho dalších, o kterých jsme se zatím nezmiňovali. Jsou to:
append(x)
a[len(a):] = [x]
.
extend(L)
a[len(a):] = L
.
insert(i, x)
a.insert(0, x)
vloží prvek na začátek
seznamu a a.insert(len(a), x)
je ekvivalentní a.append(x)
.
remove(x)
x
. Není-li
prvek v seznamu nalezen, dojde k výjimce.
pop([i])
a.pop()
odstraní a vrátí hodnotu posledního prvku
seznamu.
index(x)
x
v seznamu. Není-li prvek v seznamu
nalezen, dojde k výjimce.
count(x)
x
v celém seznamu.
sort()
reverse()
Příklad, který ukazuje jak používat většinou metod seznamů:
>>> a = [66.6, 333, 333, 1, 1234.5] >>> print a.count(333), a.count(66.6), a.count('x') 2 1 0 >>> a.insert(2, -1) >>> a.append(333) >>> a [66.6, 333, -1, 333, 1, 1234.5, 333] >>> a.index(333) 1 >>> a.remove(333) >>> a [66.6, -1, 333, 1, 1234.5, 333] >>> a.reverse() >>> a [333, 1234.5, 1, 333, -1, 66.6] >>> a.sort() >>> a [-1, 1, 66.6, 333, 333, 1234.5]
Metody append() a pop() činí ze seznamů snadno použitelné zásobníky typu LIFO - poslední přidaný prvek je odebrán jako první. Pro přidání prvku na vrchol zásobníku použijeme metodu append() a pro odebrání prvku z vrcholu zásobníku pak metodu pop() bez explicitního udání indexu. Například:
>>> stack = [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> stack [3, 4, 5, 6, 7] >>> stack.pop() 7 >>> stack [3, 4, 5, 6] >>> stack.pop() 6 >>> stack.pop() 5 >>> stack [3, 4]
Stejně jednoduše lze seznamy použít i jako fronty FIFO - první vložený prvek je
odebrán také jako první. Pro přidání prvku na konec frony použijeme metodu
append(). Pro získání prvního prvku z fronty použijeme metodu
pop() s indexem 0
. Například:
>>> fronta = ["Python", "Perl", "PHP"] >>> fronta.append("Ruby") >>> fronta.append("Lisp") >>> fronta.pop(0) 'Python' >>> fronta.pop(0) 'Perl' >>> fronta ['PHP', 'Ruby', 'Lisp']
Existují tři interní funkce, které jsou velice užitečné pro manipulace se seznamy: filter(), map() a reduce().
"filter(funkce, sekvence)" vrátí sekvenci stejného typu
jako sekvence složenou z těch prvků, pro které je
funkce(prvek)
pravdivým logickým výrazem. Příklad pro
výpočet některých prvočísel:
>>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23]
"map(funkce, sekvence)" zavolá funkci
funkce(prvek)
pro každý prvek sekvence sekvence
a vrátí seznam vrácených hodnot. Například výpočet druhých mocnin:
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
Funkci map() může být předáno více než jedna sekvence, funkce
pak musí mít tolik argumentů, kolik je použito sekvencí a je volána s hodnotami
odpovídajícím prvkům z jednotlivých sekvencí (nebo s hodnotou None
,
jestliže jedna sekvence je kratší než druhá). Jestliže na místě funkce je
předána hodnota None
, je za argument funkce dosazena funkce
vracející své argumenty.
Zkombinováním těchto dvou speciálních případů získáme volání "map(None, seznam1, seznam2)", které je konvencí pro převedení dvojice seznamů na seznam dvojic. Například:
>>> seq = range(8) >>> def square(x): return x*x ... >>> map(None, seq, map(square, seq)) [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]
"reduce(funkce, sekvence)" vrátí jedinou hodnotu získanou opakovaným voláním funkce funkce, které jsou nejprve předány první dva prvky sekvence, pak její výsledek a další prvek atd. Takto lze vypočítat třeba součet čísel od 1 do 10:
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55
Jestliže sekvence obsahuje jen jediný prvek, je vrácena hodnota tohoto prvku, jestliže je sekvence prázdná, dojde k výjimce.
Funkci reduce() může být předán ještě třetí argument indikující počáteční hodnotu. V tomto případě je pro prázdnou sekvenci vrácena tato počáteční hodnota. Poprvé je funkce aplikována na počáteční hodnotu a první prvek, pak na výsledek a další prvek atd. Například:
>>> def sum(seq): ... def add(x,y): return x+y ... return reduce(add, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0
Konstruktor seznamu je standardní cestou k vytvoření seznamu bez použití funkcí map(), filter() a nebo anonymních funkcí. Výsledná definice seznamu je mnohdy čistější než seznam vytvořený za použití výše uvedených fukcí. Každý konstruktor seznamu sestává z výrazu následovaným klauzulí for a žádnou nebo více for nebo if klauzulí. Výsledkem bude seznam získaný vyhodnocením výrazu v kontextu klauzulí for a if, které ho následují. Jestliže výraz má být vyhodnocen jako tuple, musí být uzávorkován.
>>> ovoce = [' banán', ' rajče ', 'protlak '] >>> [zbran.strip() for zbran in ovoce] ['banán', 'rajče', 'protlak'] >>> vec = [2, 4, 6] >>> [3*x for x in vec] [6, 12, 18] >>> [3*x for x in vec if x > 3] [12, 18] >>> [3*x for x in vec if x < 2] [] >>> [{x: x**2} for x in vec] [{2: 4}, {4: 16}, {6: 36}] >>> [[x,x**2] for x in vec] [[2, 4], [4, 16], [6, 36]] >>> [x, x**2 for x in vec] # CHYBA - jsou vyžadovány závorky File "<stdin>", line 1, in ? [x, x**2 for x in vec] ^ SyntaxError: invalid syntax >>> [(x, x**2) for x in vec] [(2, 4), (4, 16), (6, 36)] >>> vec1 = [2, 4, 6] >>> vec2 = [4, 3, -9] >>> [x*y for x in vec1 for y in vec2] [8, 6, -18, 16, 12, -36, 24, 18, -54] >>> [x+y for x in vec1 for y in vec2] [6, 5, -7, 8, 7, -5, 10, 9, -3] >>> [vec1[i]*vec2[i] for i in range(len(vec1))] [8, 12, -54]
Příkaz del je možné použít k odstranění prvku ze seznamu na určeném indexu, aniž bychom byli nuceni znát jeho hodnotu (což vyžaduje metoda remove(x)). Tento příkaz může být také použit pro odstranění určité slice ze seznamu (dříve jsme to dělali přiřazením prázdného seznamu této slice). Například:
>>> a [-1, 1, 66.6, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.6, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.6, 1234.5]
Příkaz del může být také použit pro odstranění celých proměnných:
>>> del a
Odkazování se na jméno a
po tomto příkazu vede k chybě (tedy pokud mu
nebyla znovu přiřazena nějaká hodnota). Další použití příkazu del
uvidíme později.
Jak jsme viděli, seznamy a řetězce mají mnoho společných vlastností jako možnost indexování nebo slice konstrukce. Seznamy a řetězce jsou příkladem sekvenčních datových typů. Python podporuje ještě jeden standardní sekvenční datový typ - tuple. Poněvadž se jazyk Python stále vyvíjí, mohou být v budoucny přidány další.
Tuple se sestává z několika hodnot oddělených čárkou, třeba:
>>> t = 12345, 54321, 'ahoj!' >>> t[0] 12345 >>> t (12345, 54321, 'ahoj!') >>> # Tuple mohou být skládány: ... u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'ahoj!'), (1, 2, 3, 4, 5))
Jak jste viděli, zobrazené tuple jsou vždy uzavřeny do závorek. Vložené tuple jsou samozřejmě intepretovány korektně. Tuple mohou být zadávány s nebo bez obklopujících závorek, závorky jsou však většinou vyžadovány, je-li tuple součástí většího výrazu.
Tuple mají mnoho použití. Například páry souřadnic (x, y), záznamy o zaměstancích v databázi apod. Tuple, podobně jako řetězce, jsou neměnné -- není možné přiřadit hodnotu určitému prvku tuple (můžete si však vypomoci slice konstrukcemi a spojením výsledných řezů). Také je možné vytvořit tuple, které obsahují proměnné objekty - třeba seznamy.
Speciálním případem je vytváření prázdné tuple a tuple obsahující jeden prvek. Prázdná tuple se vytvoří prázdným párem závorek, tuple s jedním prvkem získáme zápisem hodnoty následované čárkou (není nutné ji uzavírat do závorek). Například:
>>> prazdna = () >>> singleton = 'ahoj', # <-- nezapomeňte ukončující čárku >>> len(prazdna) 0 >>> len(singleton) 1 >>> singleton ('ahoj',)
Výraz t = 12345, 54321, 'ahoj!'
je příkladem skládání tuple:
hodnotu 12345
, 54321
a 'ahoj'
jsou složeny v tuple. Opačná
operace je také možná:
>>> x, y, z = t
Ta je nazývána, překvapivě, rozklad sekvencí. Rozklad sekvencí vyžaduje, aby seznam proměnných na levé straně byl stejně dlouhý jako sekvence na straně druhé. Pamatujte, že vícenásobné přiřazení je pouhou kombinací skládání tuple a rozkladu sekvencí.
Existuje malá asymetrie: skládání více hodnot vždy vytvoří tuple, ale rozklad funguje pro libovolnou sekvenci.
Dalším užitečným datovým typem, kterým Python disponuje je slovník. Slovníky, někdy také nazývané "asociativní pole", jsou narozdíl od sekvencí, které jsou indexovány pomocí čísel, indexovány klíči. Klíč může být libovolný neměnný typ, např. čísla nebo řetězce. Tuple mohou být použity jako klíče pouze když obsahují jen řetězce, čísla nebo tuple, jestliže tuple přímo nebo nepřímo obsahuje proměnný datový typ, nemůže být použita jako klíč. Žádný seznam nemůže být použit jako klíč, protože seznamy mohou být modifikovány za použití jejich metod, o přiřazení hodnot jednotlivým prvkům ani nemluvě.
Nejlepší je slovník považovat jako neuspořádanou množinu párů
klíč: hodnota, kde klíč musí být v rámci tohoto slovníku unikátní.
Pár složených závorek vytvoří prázdný slovník: {}
. Umístěním párů
klíč: hodnota oddělených čárkou mezi tyto závorku vytvoříme slovník
s definovanými klíči.
Slovníky podporují ukládání a čtení hodnot o zadaném klíči. Rovněž je možné
smazat pár klíč: hodnota pomocí příkazu del
. Jestliže uložíte novou
hodnotu pod klíčem, který již slovník obsahuje, dojde k přepsání položky a stará
hodnota je zapomenuta. Pokus o získání hodnoty pomocí neexistujícího klíče
vede k výjimce.
Metoda keys()
, kterou mají všechny slovníky, vrátí seznam všech klíčů
použitých ve slovníku v náhodném pořadí (jestliže jej chcete seřazený, použijte
metodu sort()
výsledného seznamu). Pro kontrolu, jestli je klíč obsažen
ve slovníku, použijte jeho metodu has_key()
.
Zde je malý příklad použití slovnkíku:
>>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel {'sape': 4139, 'guido': 4127, 'jack': 4098} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel {'guido': 4127, 'irv': 4127, 'jack': 4098} >>> tel.keys() ['guido', 'irv', 'jack'] >>> tel.has_key('guido') 1
Podmínky, použité výše v konstrukcích while
a if
, se nemusí
sestávat jen z operátorů porovnávání.
Operátory in
a not in
testují, jestli sekvence obsahuje
(resp. neobsahuje) hodnotu. Operátory is
a not is
porovnávají dva
objekty, jestli jsou to opravdu tytéž objekty, význam mají jen u proměnných
typů jako seznamy nebo slovníky. Všechny operátory porovnání mají stejnou
prioritu, která je nižší než mají všechny numerické operátory.
Porovnání může být zřetězeno. Například a < b == c
testuje jestli
a
je menší než b
a zároveň b
je rovno c
.
Porovnání mohou být kombinována za použití Booleových operátorů and
a or
a výsledek porovnání (libovolného logického výrazu) může být
znegován operátorem not
. Tyto všechny operátory mají ještě nižší prioritu
než operátory porovnání. A mezi nimi ještě not
má prioritu nejvyšší
a or
nejnižší, takže A and not B or C
je ekvivalentní zápisu
(A and (not B)) or C
. Samozřejmě je možné použít závorky pro úpravu
priority operátorů.
Booleovské operátory and
a or
jsou takzvané operátory se
zkráceným vyhodnocováním: jejich argumenty jsou vyhodnocovány zleva
doprava a vyhodnocování se zastaví, když je určen výsledek. Tj. jestliže
A
a C
jsou pravdivé, ale B
je nepravdivý, výraz A
and B and C
nevyhodnotí výraz C.
Je možné přiřadit výsledek porovnání nebo Booleovského výrazu nějaké proměnné. Například:
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim'
V Pythonu, narozdíl od C, se nemůže vyskytovat přiřazení uvnitř výrazu.
Programátorům v C to může vadit, ale Python se tímto vyhýbá mnoha chybám
programátora, ke kterým dojde zapsáním =
ve výrazu namísto ==
.
Sekvenční objekty mohou být porovnány s dalšími objekty se stejným typem. Porovnání se děje lexikograficky: nejprve jsou porovnány dva první prvky, jestliže se liší, pak se na základě jejich porovnání určí výsledek porovnání celých sekvencí, jestliže jsou stejné, dojde k porovnání dalších dvou prvků atd. dokud nedojde k vyčerpání sekvence. Jetliže některé dva prvky jsou rovněž sekvenční typy dojde k opětovnému lexikografickému porovnání. Jestliže se prvky obou sekvencí rovnají, rovnají se i obě sekvence. Jestliže jedna sekvence je delší než druhé a ve stejně dlouhé části se shodují, pak ta kratší je vyhodnocena jako menší (ve smyslu operátorů porovnání). Lexikografické porovnávání řetězců používá pro jednotlivé znaky ASCII kódování. Některé příklady porovnání jednotlivých sekvencí stejného typu:
(1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
Porovnávání objektů různých typů je rovněž možné. Typy jsou porovnávány za použití jejich jmen. Takže seznam je vždy meněí než řetězec, řetězec je vždy menší než tuple apod. Různé typy čísel jsou vždy porovnávány s ohledem na jejich číselnou hodnotu, 0 je tedy totéž, co 0.0 atd. 5.1