Nacházíte se zde: Domů ‣ Ponořme se do Pythonu 3 ‣
Úroveň obtížnosti: ♦♦♢♢♢
❝ Wonder is the foundation of all philosophy, inquiry its progress, ignorance its end. ❞
(Zvědavost je základem celé filozofie, hledání odpovědí na otázky ji žene vpřed, ignorance ji zabíjí.)
— Michel de Montaigne
Datové typy. Přestaňme si na chvíli všímat našeho prvního pythonovského programu a pojďme si popovídat o datových typech. Každá hodnota v Pythonu je určitého datového typu, ale u proměnných nemusíme datový typ deklarovat. Jak to tedy funguje? Při každém přiřazení hodnoty do proměnné si Python zjistí, jakého typu hodnota je, a vnitřně si to eviduje.
Python používá mnoho přirozených datových typů (ve smyslu „přirozených pro Python“). Uveďme zde ty hlavní:
True
nebo False
.
1
a 2
), reálná (float; 1.1
a 1.2
), zlomky (fraction; 1/2
and 2/3
), nebo dokonce čísla komplexní.
Těch typů je samozřejmě víc. V Pythonu je vše objektem, proto musí existovat také typy jako modul, funkce, třída, metoda, soubor, a dokonce přeložený kód. S některými z nich už jsme se setkali: moduly mají jména, funkce mají docstring
atd. O třídách se dozvíte v kapitole Třídy a iterátory, o souborech v kapitole Soubory.
Řetězce a bajty jsou důležité do té míry — a jsou také dost komplikované —, že jim je věnována samostatná kapitola. Nejdříve se podívejme na ty zbývající.
⁂
Objekt booleovského typu nabývá buď hodnoty true (pravda) nebo false (nepravda). Pro přímé přiřazení booleovských hodnot definuje Python dvě konstanty, příhodně pojmenované True
a False
. Booleovská hodnota může vzniknout také vyhodnocením výrazu. Na některých místech (jako u příkazu if
) Python dokonce předpokládá, že se výraz vyhodnotí do podoby booleovské hodnoty. Těmto místům se říká booleovský kontext. V booleovském kontextu můžeme použít téměř libovolný výraz. Python se pokusí získat jeho pravdivostní hodnotu. Pravidla, podle kterých se v booleovském kontextu výsledek chápe jako pravdivý nebo nepravdivý (true nebo false), jsou pro různé datové typy různá. (Jakmile uvidíte dále v této kapitole konkrétní příklady, bude vám to dávat větší smysl.)
Vezměme si například následující úryvek z humansize.py
:
if size < 0:
raise ValueError('number must be non-negative')
Proměnná size obsahuje celé číslo, 0 je celé číslo a <
je číselný operátor. Výsledek výrazu size < 0
má vždy booleovskou hodnotu. V pythonovském shellu si vyzkoušejte následující:
>>> size = 1 >>> size < 0 False >>> size = 0 >>> size < 0 False >>> size = -1 >>> size < 0 True
V důsledku problematického dědictví z Pythonu 2 se s booleovskými hodnotami může zacházet jako s čísly. True
je 1
; False
je 0.
>>> True + True 2 >>> True - False 1 >>> True * False 0 >>> True / False Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: int division or modulo by zero
Ajajaj! Takové věci nedělejte. Zapomeňte, že jsem se o tom vůbec zmínil.
⁂
Čísla jsou obdivuhodná. Můžete si je vybrat z tak ohromného množství. Python podporuje jak celá čísla (integer), tak čísla reálná (floating point). Nerozlišují se deklarací datového typu. Python je od sebe poznává podle přítomnosti nebo nepřítomnosti desetinné tečky.
>>> type(1) ① <class 'int'> >>> isinstance(1, int) ② True >>> 1 + 1 ③ 2 >>> 1 + 1.0 ④ 2.0 >>> type(2.0) <class 'float'>
type()
. Jak se dalo čekat, hodnota 1
je typu int
.
isinstance()
ověřit, zda hodnota či proměnná odpovídá zadanému typu.
int
k int
vzniká výsledek typu int
.
int
k float
vzniká výsledek typu float
. Aby mohl Python provést sčítání, vynutí si převod typu int
na float
. Poté vrátí výsledek typu float
.
Jak jste zrovna viděli, některé operátory (například sčítání) mohou podle potřeby vynutit převod celého čísla na číslo reálné. Ale k převodu je můžete donutit taky vy sami.
>>> float(2) ① 2.0 >>> int(2.0) ② 2 >>> int(2.5) ③ 2 >>> int(-2.5) ④ -2 >>> 1.12345678901234567890 ⑤ 1.1234567890123457 >>> type(1000000000000000) ⑥ <class 'int'>
float()
můžeme explicitně vynutit převod int
(typ pro celé číslo) na float
(typ pro reálné číslo).
int()
můžeme vynutit převod float
na int
.
int()
nezaokrouhluje, ale odsekává.
int()
odsekává desetinnou část u záporných čísel směrem k nule. Jde o funkci opravdového odsekávání, ne o funkci floor
(tj. u záporných čísel dojde ke zvětšení čísla, protože například –2.5
se změní na –2
).
float
jsou uložena s přesností na 15 desetinných míst.
☞Python 2 měl oddělené typy
int
along
. Datový typint
byl omezen konstantousys.maxint
, která byla platformově závislá, ale obvykle nabývala hodnoty232-1
. Python 3 má pouze jeden celočíselný typ, který se chová většinou jako původní typlong
z Pythonu 2. Detaily naleznete v PEP 237.
S čísly můžete dělat všechno možné.
>>> 11 / 2 ① 5.5 >>> 11 // 2 ② 5 >>> −11 // 2 ③ −6 >>> 11.0 // 2 ④ 5.0 >>> 11 ** 2 ⑤ 121 >>> 11 % 2 ⑥ 1
/
provádí dělení. Vrací výsledek typu float
dokonce i v případě, že činitel i jmenovatel jsou typu int
.
//
provádí svým způsobem podivné celočíselné dělení. Pokud je výsledek kladný, můžete o něm uvažovat, že vznikl odseknutím desetinných míst (tedy nikoliv zaokrouhlením). Ale pozor na to.
//
zaokrouhlení „nahoru“ k nejbližšímu celému číslu. Z matematického hlediska zaokrouhluje „dolů“, protože −6
je menší než −5
. Ale pokud byste očekávali, že dojde k odseknutí na −5
, tak byste se nachytali.
//
nevrací celé číslo vždy. Pokud je čitatel nebo jmenovatel typu float
, bude výsledek sice opět zaokrouhlen na celé číslo, ale výsledná hodnota bude typu float
.
**
znamená „umocněno na“. 112
je 121
.
%
vrací zbytek po celočíselném dělení. 11
děleno 2
je 5
a zbytek je 1
. Takže výsledkem bude 1
.
☞V Pythonu 2 obvykle operátor
/
prováděl celočíselné dělení. Ale když jste ve svém kódu použili speciální direktivu, mohli jste jeho význam přepnout na reálné dělení. V Pythonu 3 operátor/
vyjadřuje vždy dělení s reálným výsledkem (floating point division). Na detaily se podívejte do PEP 238.
Python vás neomezuje jen na celá a reálná čísla. Zvládne celou tu fantastickou matiku, kterou jste se učili na střední škole a rychle jste ji zapomněli.
>>> import fractions ① >>> x = fractions.Fraction(1, 3) ② >>> x Fraction(1, 3) >>> x * 2 ③ Fraction(2, 3) >>> fractions.Fraction(6, 4) ④ Fraction(3, 2) >>> fractions.Fraction(0, 0) ⑤ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "fractions.py", line 96, in __new__ raise ZeroDivisionError('Fraction(%s, 0)' % numerator) ZeroDivisionError: Fraction(0, 0)
fractions
.
Fraction
a předáme mu čitatele a jmenovatele.
Fraction
. 2 * (1/3) = (2/3)
Fraction
zlomky automaticky krátí. (6/4) = (3/2)
Python zvládne i základy trigonometrie.
>>> import math >>> math.pi ① 3.1415926535897931 >>> math.sin(math.pi / 2) ② 1.0 >>> math.tan(math.pi / 4) ③ 0.99999999999999989
math
definuje konstantu π, čili poměr mezi obvodem kružnice a jejím průměrem.
math
zvládá všechny základní trigonometrické funkce včetně sin()
, cos()
, tan()
a varianty jako asin()
.
tan(π / 4)
by měla vrátit 1.0
a ne 0.99999999999999989
.
Čísla můžete použít v booleovském kontextu — například v příkazu if
. Nulové hodnoty se interpretují jako false, nenulové jako true.
>>> def is_it_true(anything): ① ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(1) ② yes, it's true >>> is_it_true(-1) yes, it's true >>> is_it_true(0) no, it's false >>> is_it_true(0.1) ③ yes, it's true >>> is_it_true(0.0) no, it's false >>> import fractions >>> is_it_true(fractions.Fraction(1, 2)) ④ yes, it's true >>> is_it_true(fractions.Fraction(0, 1)) no, it's false
0.0
se chápe jako false. Ale bacha na tu poslední hodnotu! Pokud dojde k sebemenší zaokrouhlovací chybě (což není nemožné, jak jste si mohli všimnout v předchozí podkapitole), pak bude Python testovat místo nuly například 0.0000000000001
a vrátí hodnotu True
.
Fraction(0, n)
se pro všechny hodnoty n vyhodnotí jako false. Všechny ostatní zlomky se vyhodnotí jako true.
⁂
Seznamy jsou v Pythonu nejpoužívanějšími datovými typy. Když řeknu „seznam“ (anglicky list [list]), může vás napadnout „pole, jehož velikost musím předem deklarovat, které může obsahovat jen prvky stejného typu atd.“. Tímto směrem neuvažujte. Seznamy jsou mnohem lepší.
☞Pythonovský seznam se podobá poli (array) v Perl 5. Proměnné polí v jazyce Perl 5 vždycky začínají znakem
@
. Pythonovské proměnné můžou být pojmenovány zcela libovolně. Python si vnitřně eviduje jejich datový typ.
☞Pythonovský seznam má větší možnosti než pole (array) v jazyce Java. (Ačkoliv pokud je to vše, co od života očekáváte, můžete jej tímto způsobem používat.) Podobnější je mu třída
ArrayList
, která umožňuje uchovávání libovolných objektů a při přidání nových položek se může dynamicky zvětšit.
Seznam můžeme vytvořit snadno. Čárkami oddělené hodnoty uzavřeme do hranatých závorek.
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] ① >>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[0] ② 'a' >>> a_list[4] ③ 'example' >>> a_list[-1] ④ 'example' >>> a_list[-3] ⑤ 'mpilgrim'
a_list[0]
.
a_list[4]
, protože indexování začíná nulou.
a_list[-1]
.
a_list[-n] == a_list[len(a_list) - n]
. Takže pro náš seznam pak platí a_list[-3] == a_list[5 - 3] == a_list[2]
.
Jakmile máme vytvořen seznam, můžeme získat jakoukoliv jeho část. Anglicky se tomu říká „slicing the list“, což můžeme přeložit jako „vykrajování ze seznamu“ nebo „výřez ze seznamu“ nebo — z pohledu abstraktního záměru — vytváření podseznamu.
>>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[1:3] ① ['b', 'mpilgrim'] >>> a_list[1:-1] ② ['b', 'mpilgrim', 'z'] >>> a_list[0:3] ③ ['a', 'b', 'mpilgrim'] >>> a_list[:3] ④ ['a', 'b', 'mpilgrim'] >>> a_list[3:] ⑤ ['z', 'example'] >>> a_list[:] ⑥ ['a', 'b', 'mpilgrim', 'z', 'example']
a_list[1]
) až po položku (ale vyjma) s druhým indexem výřezu (v našem případě a_list[3]
).
a_list[0:3]
vrací první tři položky seznamu počínaje položkou a_list[0]
až po a_list[3]
vyjma (ta už se nevrací).
a_list[:3]
vede ke stejnému výsledku jako a_list[0:3]
, protože počáteční nula se dosadí jako implicitní hodnota.
a_list[3:]
ke stejnému výsledku jako a_list[3:5]
. A najdeme zde potěšitelnou symetrii. V našem pětiprvkovém seznamu vrací zápis a_list[:3]
první tři položky a a_list[3:]
vrací zbývající dvě. Obecně platí, že a_list[:n]
vždy vrátí prvních n položek a a_list[n:]
vrátí zbytek — nezávisle na délce seznamu.
a_list[:]
je tedy zkratkou pro získání úplné kopie seznamu.
Položku můžeme do seznamu přidat čtyřmi způsoby.
>>> a_list = ['a'] >>> a_list = a_list + [2.0, 3] ① >>> a_list ② ['a', 2.0, 3] >>> a_list.append(True) ③ >>> a_list ['a', 2.0, 3, True] >>> a_list.extend(['four', 'Ω']) ④ >>> a_list ['a', 2.0, 3, True, 'four', 'Ω'] >>> a_list.insert(0, 'Ω') ⑤ >>> a_list ['Ω', 'a', 2.0, 3, True, 'four', 'Ω']
+
spojí seznamy a vytvoří nový seznam. Seznam může obsahovat libovolný počet položek. Neexistuje zde žádný limit (pouze velikost dostupné paměti). Ale co se týká paměti, měli bychom si dát pozor na to, že spojením seznamů vzniká v paměti další seznam. V našem případě je nový seznam ihned přiřazen do existující proměnné a_list. Takže tento řádek kódu ve skutečnosti představuje dvoufázový proces — spojení (konkatenace) a přiřazení —, který může u rozsáhlých seznamů (dočasně) spotřebovat velké množství paměti.
append()
přidává jednu položku na konec seznamu. (Teď už máme v seznamu položky se čtyřmi rozdílnými datovými typy!)
extend()
přebírá jeden argument, kterým je seznam. Každý jeho prvek připojí na konec původního seznamu (append).
insert()
vloží do seznamu jednu položku. Prvním argumentem je index první položky seznamu, která bude z této pozice odsunuta. Položky seznamu nemusí být jedinečné. Například v našem případě teď seznam obsahuje dvě samostatné položky s hodnotou 'Ω'
: první položku (a_list[0]
) a poslední položku (a_list[6]
).
☞Volání metody
a_list.insert(0, value)
se podobá použití funkceunshift()
v jazyce Perl. Vloží prvek na začátek seznamu a index všech ostatních položek se zvýší, aby vzniklo potřebné místo.
Podívejme se podrobněji na rozdíly mezi append()
a extend()
.
>>> a_list = ['a', 'b', 'c'] >>> a_list.extend(['d', 'e', 'f']) ① >>> a_list ['a', 'b', 'c', 'd', 'e', 'f'] >>> len(a_list) ② 6 >>> a_list[-1] 'f' >>> a_list.append(['g', 'h', 'i']) ③ >>> a_list ['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']] >>> len(a_list) ④ 7 >>> a_list[-1] ['g', 'h', 'i']
extend()
přebírá jeden argument, kterým je vždy seznam, a přidá každý jeho prvek do seznamu a_list.
extend()
o seznam s dalšími třemi položkami, dostanete seznam s šesti položkami.
append()
přebírá jeden argument, který může být libovolného datového typu. Na tomto řádku předáváme metodě append()
seznam s třemi položkami.
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list.count('new') ① 2 >>> 'new' in a_list ② True >>> 'c' in a_list False >>> a_list.index('mpilgrim') ③ 3 >>> a_list.index('new') ④ 2 >>> a_list.index('c') ⑤ Traceback (innermost last): File "<interactive input>", line 1, in ? ValueError: list.index(x): x not in list
count()
vrací počet výskytů určité hodnoty v seznamu (což se dalo čekat).
in
o něco rychlejší než volání metody count()
. Operátor in
vždy vrací True
nebo False
. Neřekne vám, kolikrát se daná hodnota v seznamu vyskytuje.
in
ani metoda count()
vám ale neřeknou, kde se v seznamu hodnota vyskytuje. Pokud chcete zjistit, kde se hodnota v seznamu nachází, použijte metodu index()
. Pokud neřeknete jinak, bude prohledávat celý seznam. Ale nepovinným druhým argumentem můžete zadat index (od nuly), na kterém má hledání začít. A můžeme dokonce zadat nepovinný třetí argument s indexem místa, kde má hledání skončit.
index()
najde první výskyt zadané hodnoty v seznamu. V tomto případě se hodnota 'new'
vyskytuje v seznamu dvakrát: a_list[2]
a a_list[4]
. Ale metoda index()
vrátí jen index prvního výskytu.
index()
výjimku.
Počkat! Co? Je to tak. Pokud metoda index()
nenajde v seznamu zadanou hodnotu, vyvolá výjimku. Jde o zjevně odlišné chování ve srovnání s jinými jazyky, které vracejí nějakou neplatnou hodnotu indexu (jako například -1
). Ze začátku se vám to může zdát protivné, ale myslím, že to časem oceníte. Znamená to, že program zhavaruje v místě vzniku problému místo toho, aby potichu a divně selhal o chvíli později. Vzpomeňte si, že hodnota -1
je platným indexem prvku v seznamu. Kdyby metoda index()
místo výjimky vracela hodnotu -1
, mohlo by to vést k poměrně nezábavným zážitkům při ladění.
Seznamy se mohou automaticky nafukovat a smršťovat. Jejich expanzi už jsme si ukázali. Odstraňování položek ze seznamu můžeme také provést několika způsoby.
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list[1] 'b' >>> del a_list[1] ① >>> a_list ['a', 'new', 'mpilgrim', 'new'] >>> a_list[1] ② 'new'
del
.
1
poté, co jsme položku s indexem 1
odstranili, nedojde k chybě. Poziční index všech položek, které následují za rušenou položkou, bude posunut tak, aby byla vzniklá mezera zaplněna.
Že neznáte ten správný poziční index? Žádný problém. Odstranění položek můžete předepsat také jejich hodnotou.
>>> a_list.remove('new') ① >>> a_list ['a', 'mpilgrim', 'new'] >>> a_list.remove('new') ② >>> a_list ['a', 'mpilgrim'] >>> a_list.remove('new') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.remove(x): x not in list
remove()
. Metoda remove()
přebírá zadanou hodnotu a odstraní ze seznamu její první výskyt. A opět. Všechny položky, které následují za rušenou položkou, budou posunuty tak, aby byla vzniklá mezera zaplněna. V seznamech nikdy nevznikají díry.
remove()
můžete volat, kdykoliv se vám to hodí. Ale pokud se pokusíte o odstranění položky s hodnotou, která se v seznamu nevyskytuje, bude vyvolána výjimka.
Další zajímavou metodou seznamu je pop()
. Metoda pop()
představuje další způsob odstraňování položek ze seznamu, ale s malou fintou.
>>> a_list = ['a', 'b', 'new', 'mpilgrim'] >>> a_list.pop() ① 'mpilgrim' >>> a_list ['a', 'b', 'new'] >>> a_list.pop(1) ② 'b' >>> a_list ['a', 'new'] >>> a_list.pop() 'new' >>> a_list.pop() 'a' >>> a_list.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: pop from empty list
pop()
bez argumentů, odstraní poslední položku seznamu a vrátí hodnotu, která byla odstraněna.
pop()
můžeme ze seznamu odstranit libovolnou položku. Jednoduše jí předáme poziční index. Odstraní požadovanou položku, posune následující položky tak, aby zaplnila mezeru, a vrátí odstraněnou hodnotu.
pop()
pro prázdný seznam, vznikne výjimka.
☞Volání metody seznamu
pop()
bez argumentu se podobá volání funkcepop()
v jazyce Perl. Odstraní poslední položku seznamu a vrátí hodnotu, která byla odstraněna. V jazyce Perl existuje také funkceshift()
, která odstraní první položku a vrátí její hodnotu. Jde o ekvivalent pythonovského volánía_list.pop(0)
.
Seznam můžeme použít také v booleovském kontextu, jako například v příkazu if
.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true([]) ① no, it's false >>> is_it_true(['a']) ② yes, it's true >>> is_it_true([False]) ③ yes, it's true
⁂
N-tice (anglicky tuple) se chová jako neměnitelný seznam. Jakmile je n-tice jednou vytvořena, nedá se nijak změnit.
>>> a_tuple = ("a", "b", "mpilgrim", "z", "example") ① >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple[0] ② 'a' >>> a_tuple[-1] ③ 'example' >>> a_tuple[1:3] ④ ('b', 'mpilgrim')
a_tuple[0]
.
Hlavní rozdíl mezi n-ticemi a seznamy je ten, že n-tice nemohou být změněny. Z technického pohledu říkáme, že n-tice jsou neměnitelné (anglicky immutable). Prakticky se to projevuje tak, že neposkytují žádnou metodu, která by nám je dovolila změnit. Seznamy mají metody jako append()
, extend()
, insert()
, remove()
a pop()
. N-tice žádnou z těchto metod nemají. Z n-tice můžeme vytvořit výřez (protože se vytváří nová n-tice), můžeme zjišťovat, zda n-tice obsahuje určitou hodnotu (protože tím ke změně n-tice nedochází) a… to je všechno.
# pokračování předchozího příkladu >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple.append("new") ① Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'append' >>> a_tuple.remove("z") ② Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'remove' >>> a_tuple.index("example") ③ 4 >>> "z" in a_tuple ④ True
append()
ani extend()
.
remove()
nebo pop()
.
in
pro testování, zda n-tice obsahuje zadaný prvek.
Takže na co jsou n-tice dobré?
assert
, který by kontroloval, zda jsou data konstantní. Překonat to můžeme jen záměrně (a s využitím specifické funkce).
☞N-tice mohou být převedeny na seznamy a naopak. Zabudovaná funkce
tuple()
může převzít seznam a vrací n-tici se stejnými prvky. A naopak funkcelist()
může převzít zadanou n-tici a vrací seznam. Z pohledu účinku tedy funkcetuple()
seznam zmrazí a funkce naopaklist()
rozpustí n-tici.
N-tice můžeme použít v booleovském kontextu, jako například v příkazu if
.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(()) ① no, it's false >>> is_it_true(('a', 'b')) ② yes, it's true >>> is_it_true((False,)) ③ yes, it's true >>> type((False)) ④ <class 'bool'> >>> type((False,)) <class 'tuple'>
Následuje parádní programátorská zkratka. V Pythonu můžete n-tici použít pro přiřazení více hodnot najednou.
>>> v = ('a', 2, True)
>>> (x, y, z) = v ①
>>> x
'a'
>>> y
2
>>> z
True
(x, y, z)
je n-tice s třemi proměnnými. Přiřazení jedné do druhé vede k přiřazení každé z hodnot n-tice v do jednotlivých proměnných v uvedeném pořadí.
Využít se toho dá všemožnými způsoby. Dejme tomu, že chcete pojmenovat řadu hodnot. K rychlému přiřazení po sobě jdoucích hodnot můžete využít zabudovanou funkci range()
a vícenásobné přiřazení.
>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ① >>> MONDAY ② 0 >>> TUESDAY 1 >>> SUNDAY 6
range()
vytváří posloupnost celých čísel. (Z technického hlediska nevrací funkce range()
seznam ani n-tici, ale iterátor. Odlišnosti se naučíme později.) MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, a SUNDAY jsou proměnné, které definujeme. (Tento příklad pochází z modulu calendar
, což je malý zábavný modul, který tiskne kalendář podobně jako UNIXový program cal
. Modul calendar
definuje pro dny v týdnu celočíselné konstanty.)
0
, TUESDAY má hodnotu 1
a tak dále.
Současného přiřazení více proměnným můžeme využít také pro vytváření funkcí, které vracejí více hodnot najednou. Jednoduše v nich vrátíme n-tici se všemi požadovanými hodnotami. Ve volajícím kódu se k výsledku můžeme chovat jako k jedné n-tici, nebo jej můžeme přiřadit do více jednotlivých proměnných. Tento obrat používá řada standardních pythonovských knihoven, včetně modulu os
. O něm si něco řekneme v následující kapitole.
⁂
Množina (set) je neuspořádanou kolekcí jedinečných hodnot. Jedna množina může obsahovat hodnoty libovolného neměnitelného (immutable) datového typu. Pokud máme k dispozici dvě množiny, můžeme s nimi provádět standardní množinové operace, jako je sjednocení, průnik a rozdíl množin.
Ale nejdříve proberme základy. Množinu vytvoříme snadno.
>>> a_set = {1} ① >>> a_set {1} >>> type(a_set) ② <class 'set'> >>> a_set = {1, 2} ③ >>> a_set {1, 2}
{}
).
Množinu můžeme vytvořit i ze seznamu.
>>> a_list = ['a', 'b', 'mpilgrim', True, False, 42] >>> a_set = set(a_list) ① >>> a_set ② {'a', False, 'b', True, 'mpilgrim', 42} >>> a_list ③ ['a', 'b', 'mpilgrim', True, False, 42]
set()
. (Puntičkáři, kteří vědí, jak jsou množiny implementovány, by zde podotkli, že ve skutečnosti nejde o volání funkce, ale o vytváření instance třídy. Já vám slibuji, že se o tomto rozdílu dozvíte v této knize později. Prozatím nám bude stačit vědět, že set()
se chová jako funkce a že vrací množinu.)
Že zatím nemáte k dispozici žádné hodnoty? Žádný problém. Můžeme vytvořit prázdnou množinu.
>>> a_set = set() ① >>> a_set ② set() >>> type(a_set) ③ <class 'set'> >>> len(a_set) ④ 0 >>> not_sure = {} ⑤ >>> type(not_sure) <class 'dict'>
set()
bez argumentů.
{}
? Tímto způsobem se vyjadřuje prázdný slovník a ne množina. O slovnících se dozvíme později, ale ještě v této kapitole.
Do existující množiny můžeme přidávat hodnoty dvěma různými způsoby: metodou add()
a metodou update()
.\
>>> a_set = {1, 2} >>> a_set.add(4) ① >>> a_set {1, 2, 4} >>> len(a_set) ② 3 >>> a_set.add(1) ③ >>> a_set {1, 2, 4} >>> len(a_set) ④ 3
add()
přebírá jeden argument, který může být libovolného datového typu, a přidává zadanou hodnotu do množiny.
>>> a_set = {1, 2, 3} >>> a_set {1, 2, 3} >>> a_set.update({2, 4, 6}) ① >>> a_set ② {1, 2, 3, 4, 6} >>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) ③ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 13} >>> a_set.update([10, 20, 30]) ④ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}
update()
přebírá jeden argument, rovněž množinu, a přidá všechny její členy do původní množiny. Je to, jako kdybychom volali metodu add()
pro všechny členy množiny předané argumentem.
update()
volat s libovolným počtem argumentů. Pokud ji zavoláte s dvěma množinami, metoda update()
přidá všechny členy z každé z předaných množin do původní množiny (duplicitní hodnoty se přeskočí).
update()
umí zpracovat objekty různých datových typů, včetně seznamů. Pokud jí předáte seznam, pak metoda update()
přidá do původní množiny všechny členy seznamu.
Jednotlivé hodnoty lze z množiny odstranit třemi způsoby. První dva, discard()
a remove()
, se liší v jedné malé drobnosti.
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set {1, 3, 36, 6, 10, 45, 15, 21, 28} >>> a_set.discard(10) ① >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.discard(10) ② >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.remove(21) ③ >>> a_set {1, 3, 36, 6, 45, 15, 28} >>> a_set.remove(21) ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 21
discard()
přebírá jeden argument a zadanou hodnotu odebere z množiny.
discard()
voláme s hodnotou, která v množině neexistuje, neprovede se nic. Nevznikne chyba. Jde o prázdnou operaci.
remove()
také přebírá hodnotu jediného argumentu a také odstraňuje hodnotu z množiny.
remove()
vyvolá výjimku KeyError
.
Množiny, stejně jako seznamy, podporují metodu pop()
.
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set.pop() ① 1 >>> a_set.pop() 3 >>> a_set.pop() 36 >>> a_set {6, 10, 45, 15, 21, 28} >>> a_set.clear() ② >>> a_set set() >>> a_set.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'pop from an empty set'
pop()
odstraní jeden prvek z množiny a vrátí jeho hodnotu. Ale množiny jsou neuspořádané a neexistuje u nich nic takového jako „poslední“ hodnota. Proto také neexistuje možnost ovlivnit, která hodnota bude odstraněna. Je to zcela náhodné.
clear()
odstraní všechny prvky množiny a množina se stane prázdnou. Ve výsledku je to stejné jako provedení příkazu a_set = set()
, který vytvoří novou prázdnou množinu a přepíše původní hodnotu proměnné a_set.
pop()
pro prázdnou množinu vede k vyvolání výjimky KeyError
.
Pythonovský datový typ set
podporuje několik běžných množinových operací.
>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} >>> 30 in a_set ① True >>> 31 in a_set False >>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} >>> a_set.union(b_set) ② {1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127} >>> a_set.intersection(b_set) ③ {9, 2, 12, 5, 21} >>> a_set.difference(b_set) ④ {195, 4, 76, 51, 30, 127} >>> a_set.symmetric_difference(b_set) ⑤ {1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}
in
. Funguje stejným způsobem jako u seznamů.
union()
(sjednocení) vrací novou množinu, která obsahuje všechny prvky jak z jedné, tak z druhé množiny.
intersection()
(průnik) vrací novou množinu, která obsahuje všechny prvky nacházející se v obou množinách současně.
difference()
(rozdíl) vrací novou množinu obsahující všechny prvky, které se nacházejí v množině a_set, ale nenacházejí se v množině b_set.
symmetric_difference()
(symetrický rozdíl) vrací novou množinu obsahující všechny prvky, které se nacházejí právě v jedné z množin.
Tři z těchto metod jsou symetrické.
# pokračování předchozího příkladu >>> b_set.symmetric_difference(a_set) ① {3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127} >>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) ② True >>> b_set.union(a_set) == a_set.union(b_set) ③ True >>> b_set.intersection(a_set) == a_set.intersection(b_set) ④ True >>> b_set.difference(a_set) == a_set.difference(b_set) ⑤ False
A nakonec tu máme několik otázek, které můžeme množinám položit.
>>> a_set = {1, 2, 3} >>> b_set = {1, 2, 3, 4} >>> a_set.issubset(b_set) ① True >>> b_set.issuperset(a_set) ② True >>> a_set.add(5) ③ >>> a_set.issubset(b_set) False >>> b_set.issuperset(a_set) False
False
.
Množiny můžeme použít v booleovském kontextu, například v příkazu if
.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(set()) ① no, it's false >>> is_it_true({'a'}) ② yes, it's true >>> is_it_true({False}) ③ yes, it's true
⁂
Slovník (dictionary) je neuspořádaná kolekce dvojic klíč-hodnota. Když do slovníku přidáme klíč, musíme do něj současně přidat i hodnotu, která ke klíči patří. (Hodnotu můžeme v budoucnu kdykoliv změnit.) Pythonovské slovníky jsou optimalizované pro získávání hodnoty k zadanému klíči, ale ne naopak.
☞Pythonovský slovník se chová jako hash (čti [heš]; vyhledávací tabulka) v Perl 5. V jazyce Perl 5 začínají proměnné typu hash vždy znakem
%
. Pythonovské proměnné mohou být pojmenovány zcela libovolně. Python si vnitřně eviduje jejich datový typ.
Slovník vytvoříme snadno. Syntaxe se podobá množinové, ale místo pouhé hodnoty zadáváme dvojice klíč-hodnota. Jakmile slovník existuje, můžeme v něm vyhledávat hodnoty podle jejich klíče.
>>> a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'} ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['server'] ② 'db.diveintopython3.org' >>> a_dict['database'] ③ 'mysql' >>> a_dict['db.diveintopython3.org'] ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'db.diveintopython3.org'
'server'
je zde klíčem a k němu přidruženou hodnotou, na kterou se odkážeme zápisem a_dict['server']
, je 'db.diveintopython3.org'
.
'database'
je zde klíčem. K němu přidruženou hodnotou, na kterou se odkážeme zápisem a_dict['database']
, je 'mysql'
.
a_dict['server']
obsahuje 'db.diveintopython3.org'
, ale a_dict['db.diveintopython3.org']
vyvolá výjimku, protože 'db.diveintopython3.org'
není klíčem.
Slovníky nemají žádné předem určené omezení velikosti. Dvojici klíč-hodnota můžeme do slovníku přidat kdykoliv. Nebo můžeme měnit hodnotu příslušející ke klíči. Pokračování předchozího příkladu:
>>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['database'] = 'blog' ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'blog'} >>> a_dict['user'] = 'mark' ② >>> a_dict ③ {'server': 'db.diveintopython3.org', 'user': 'mark', 'database': 'blog'} >>> a_dict['user'] = 'dora' ④ >>> a_dict {'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'} >>> a_dict['User'] = 'mark' ⑤ >>> a_dict {'User': 'mark', 'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}
'user'
, hodnota 'mark'
) se objevila uprostřed. To, že se u prvního příkladu položky objevily seřazené, byla pouhá náhoda. Stejná náhoda je to, že se nyní jeví jako rozházené.
user
zpět na „mark“? Nikoliv! Prohlédněte si klíč pořádně. V řetězci User je napsáno velké U. Klíče slovníků jsou citlivé na velikost písmen, takže tento příkaz vytváří novou dvojici klíč-hodnota a existující hodnotu nepřepíše. Klíč se vám sice může zdát podobný, ale z pohledu Pythonu je úplně jiný.
Slovníky nejsou určeny jen pro řetězce. Hodnoty ve slovníku mohou být libovolného datového typu včetně celých čísel, booleovských hodnot, libovolných objektů nebo dokonce slovníků. Uvnitř jednoho slovníku nemusí být všechny hodnoty stejného typu. Můžeme je míchat podle potřeby. Klíče slovníků mají větší omezení, ale mohou být typu řetězec, celé číslo a několika dalších typů. Datové typy klíčů v jednom slovníku můžeme také míchat.
Se slovníky s neřetězcovými klíči a hodnotami jsme se vlastně už setkali v kapitole Váš první pythonovský program.
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
Teď to v interaktivním shellu rozkucháme.
>>> SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], ... 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']} >>> len(SUFFIXES) ① 2 >>> 1000 in SUFFIXES ② True >>> SUFFIXES[1000] ③ ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] >>> SUFFIXES[1024] ④ ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] >>> SUFFIXES[1000][3] ⑤ 'TB'
len()
, podobně jako u seznamů a množin, vrací počet klíčů ve slovníku.
in
k testování, zda je zadaný klíč ve slovníku definován.
1000
je klíčem ve slovníku SUFFIXES
. Jeho hodnotou je seznam osmi položek (osmi řetězců, abychom byli přesní).
1024
je klíčem ve slovníku SUFFIXES
. Jeho hodnotou je také seznam s osmi položkami.
SUFFIXES[1000]
obsahuje seznam, můžeme jeho jednotlivé prvky zpřístupňovat prostřednictvím indexu (od nuly).
Slovník můžeme použít v booleovském kontextu, jako například v příkazu if
.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true({}) ① no, it's false >>> is_it_true({'a': 1}) ② yes, it's true
⁂
None
None
[nan] je speciální pythonovskou konstantou. Vyjadřuje žádnou hodnotu. Ale None
není totéž co False
. None
není nula. None
není prázdný řetězec. Pokud porovnáme None
s čímkoliv jiným než s None
, vždycky dostaneme False
.
None
je jedinou „žádnou“ hodnotou. Má svůj vlastní datový typ (NoneType
). Hodnotu None
můžeme přiřadit do libovolné proměnné, ale nemůžeme vytvořit jiný objekt typu NoneType
. Všechny proměnné, jejichž hodnota je None
, jsou vzájemně shodné.
>>> type(None) <class 'NoneType'> >>> None == False False >>> None == 0 False >>> None == '' False >>> None == None True >>> x = None >>> x == None True >>> y = None >>> x == y True
None
v booleovském kontextuV booleovském kontextu se None
vyhodnocuje jako false a not None
jako true.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(None) no, it's false >>> is_it_true(not None) yes, it's true
⁂
fractions
(zlomky)
math
(matematický)
© 2001–11 Mark Pilgrim