Další základní datový typ, který si představíme –
po číslech, řetězcích, seznamech a n-ticích –
je slovník (angl. dictionary, dict
).
Představ si překladový slovník, třeba tenhle česko-anglický:
Slovník v Pythonu obsahuje záznamy, a každý záznam přiřazuje nějakému klíči nějakou hodnotu. V našem příkladu je klíči Jablko přiřazena hodnota Apple, klíči Knoflík náleží hodnota Button a klíč Myš ukazuje na Mouse.
V Pythonu by se takový slovník napsal následovně:
>>> slovnik = {'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
>>> slovnik
{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
Pozor na všechny ty symboly! V tomhle slovníku jsou klíče i hodnoty řetězce, a jsou tedy v uvozovkách. Každý klíč je od své hodnoty oddělený dvojtečkou; jednotlivé dvojice jsou od sebe oddělené čárkou. A celý slovník je uzavřený ve složených závorkách.
Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět co hledat. Konkrétně potřebuješ klíč. Ten dáš do hranatých závorek:
>>> slovnik['Jablko']
'Apple'
Je to podobné jako u seznamů, jen v hranatých závorkách není index (pořadí prvku) nebo rozmezí s dvojtečkou, ale právě klíč.
Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. Na překlad z angličtiny do češtiny bys potřebovala druhý slovník.
Co se stane, když klíč ve slovníku není?
>>> slovnik['Pes']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Pes'
Python si postěžuje na KeyError
– chybu klíče.
Podobně jako seznamy se ale slovníky dají měnit. Nový záznam vytvoříš takhle:
>>> slovnik['Pes'] = 'Dog'
>>> slovnik
{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Dog'}
Na rozdíl od překladového slovníku nemusí být Pythonní slovník seřazený podle abecedy. Není to potřeba, počítač umí rychle vyhledávat i bez seřazení.
Kdybys potřebovala změnit už existující záznam, použij stejný příkaz. K jednomu klíči může patřit jen jedna hodnota.
>>> slovnik['Pes'] = 'Power strip'
>>> slovnik
{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Power strip'}
Chceš-li ze zlovníku nějaký záznam smazat, dělá se to podobně jako
u seznamů – příkazem del
:
>>> del slovnik['Pes']
>>> slovnik
{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'}
Když budeš chtít zjistit kolik je ve slovníku záznamů,
zeptáš se podobně jako na počet znaků řetězce nebo prvků seznamu.
Použiješ funkci len()
.
>>> len(slovnik)
3
A pomocí in
můžeš zjistit, jestli slovník obsahuje daný klíč.
Funguje to opravdu jen pro klíče, ne pro přiřazené hodnoty:
>>> 'Myš' in slovnik
True
>>> 'Mouse' in slovnik
False
Když slovník projdeš cyklem for
, dostaneš klíče jednotlivých záznamů:
>>> for klic in slovnik:
... print(klic)
Jablko
Knoflík
Myš
Když bys chtěla projít místo klíčů hoodnoty, použij metodu values
,
která vrací iterátor hodnot:
>>> for hodnota in popisy_funkci.values():
... print(hodnota)
Apple
Button
Mouse
Většinou ale potřebuješ jak klíče tak hodnoty.
K tomu mají slovníky metodu items
, která vrací iterátor dvojic.
Často každou dvojici přímo rozbalíš v cyklu for
, jako se to dělá se
zip
nebo enumerate
:
>>> for klic, hodnota in popisy_funkci.items():
... print('{}: {}'.format(klic, hodnota))
Jablko: Apple
Knoflík: Button
Myš: Mouse
Existuje i metoda keys()
, která vrací klíče.
To, co keys()
, values()
a items()
vrací, jsou speciální objekty,
které kromě použití ve for
umožňují další
operace: například pracovat s klíči jako s množinou.
V dokumentaci
Pythonu je to všechno popsáno.
V průběhu iterace (tedy v rámci for
cyklu) nesmíš
do slovníku přidávat záznamy, ani záznamy odebírat:
>>> for klic in popisy_funkci:
... del popisy_funkci[klic]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
Hodnoty u už existujících klíčů ale měnit můžeš.
Slovník se dá vytvořit několika způsoby.
První, pomocí složených závorek, jsi už viděla.
Další způsob je využívá funkci dict
.
Ta, ve stylu str
, int
či list
, převede cokoli, co jde, na slovník.
Slovník je ovšem dost specifická struktura – čísla ani většina seznamů na něj převést nejdou. Můžeš ale na slovník převést jiný slovník. Nový slovník pak žije svým vlastním životem; můžeš ho měnit nezávisle na tom původním.
Druhá věc, která jde převést na slovník, je sekvence dvojic klíč/hodnota – ať už seznam:
data = [(1, 'jedna'), (2, 'dva'), (3, 'tři')]
nazvy_cisel = dict(data)
nebo jiný iterovatelný objekt:
data = enumerate(['jedna', 'dva' 'tři'])
nazvy_cisel = dict(data)
A to je vše, co se na slovník dá převést.
Jako bonus umí funkce dict
ještě
brát pojmenované argumenty.
Každé jméno argumentu převede na řetězec,
použije ho jako klíč, a přiřadí danou hodnotu:
popisy_funkci = dict(len='délka', str='řetězec', dict='slovník')
print(popisy_funkci['len'])
Pozor na to, že v tomhle případě musí být klíče
pythonní „jména“ – musí být použitelné jako jména proměnných.
Například takhle nejde zadat jako klíč řetězec
"def"
nebo "propan-butan"
.
Nejobecnější způsob vytváření slovníků je podobný tomu, co znáš u seznamů: vytvoř prázdný slovník a postupně do něj přidávej záznamy, jeden za druhým.
Řekněme, že máš slovník který přiřazuje ovoci jeho barvu:
barvy = {
'hruška': 'zelená',
'jablko': 'červená',
'meloun': 'zelená',
'švestka': 'modrá',
'ředkvička': 'červená',
'zelí': 'zelená',
'mrkev': 'červená',
}
Následující kód vytvoří slovník se změněnými barvami:
barvy_po_tydnu = {}
for ovoce, barva in barvy.items():
barvy_po_tydnu[ovoce] = 'černo-hnědo-' + barva
print(barvy_po_tydnu['jablko'])
Ke každému klíči může patřit jen jedna hodnota. Jak bys zařídila, aby hodnot víc?
Řekněme, že bys chtěla do slovníku uložit tyto telefonní kontakty:
Jak na to? Jednoduchý slovník použít nemůžeš. Pozor na následující zápis!
kontakty = {
'Katka': '4925219',
'Jirka': '7477058',
'Jirka': '3251156',
'Verča': '1019103',
}
Python v tomto případě jednotlivé záznamy uloží postupně,jako kdybys napasla:
kontakty = {}
kontakty['Katka'] = '4925219'
kontakty['Jirka'] = '7477058'
kontakty['Jirka'] = '3251156'
kontakty['Verča'] = '1019103'
A ve výsledku bude mít 'Jirka'
uložené jen jedno číslo.
Python tohle nebere jako chybu, ačkoli to často není to, co chceš.
Protože ve slovníku může být každému klíči přiřazena jen jedna hodnota, bude potřeba více hodnot směstnat do jedné. Každému kontaktu můžeš přiřadit seznam čísel:
kontakty = {
'Katka': ['4925219'],
'Jirka': ['7477058', '3251156'],
'Verča': ['1019103'],
}
Výraz jako kontakty['Katka']
pak označuje seznam,
Pokus se Katka se přestěhuje do zahraničí a pořídí si nové číslo,
můžeš napsat:
kontakty['Katka'].append('+897 3788509')
print(len(kontakty['Katka']))
print(kontakty['Katka'][-1])
del kontakty['Katka'][0]
print(kontakty['Katka'])
Do slovníku můžeš uložit použít jakoukoli hodnotu: řetězce, seznamy, nebo čísla.
uzivatel = {'jméno': 'Amálka', 'velikost nohy': 36, 'oblíbená čísla': [5, 27]}
Jako klíč jde ovšem použít jen hodnoty, podle kterých pak Python umí záznam rychle najít. A to nejsou všechny. Řetězce a čísla použít jdou:
jmena_cisel = {2: 'dva', 3: 'tři'}
Ale seznamy nebo jiné slovníky ne. Typy které se dají použít jako klíč ve slovníku se techicky označují jako „hashovatelné“ (angl. hashable). Tento termín se objevuje v chybových hláškách:
>>> jmena_seznamu = {[1, 2, 3]: 'čísla', ['a', 'b', 'c']: 'řetězce'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
N-tice jsou hashovatelné, pokud obsahují jen hashovatelné hodnoty:
>>> figurky = {('c', 1): 'bílý střelec', ('e', 8): 'černý král'}
>>> figurky['c', 1]
'střelec'
>>> jmena = {([1, 2, 3], [3, 4, 5]): 'dvojice seznamů'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Chceš-li mít všechny triky, které slovníky umí, pěkně pohromadě, můžeš si stáhnout Slovníkový tahák.
Kompletní popis slovníků najdeš v dokumentaci Pythonu.