Lekce 8 - ChainMap, NamedTuple a DeQue v Pythonu
V minulé lekci, Komprehence, lambda výrazy a funkce v Pythonu, jsme si ukázali seznamové komprehence, lambda výrazy a některé vestavěné funkce pro práci s iterovatelnými objekty.
V tomto tutoriálu kolekcí v Pythonu se budeme věnovat
třem jejich zástupcům. Konkrétně se zaměříme na třídy
ChainMap
, NamedTuple
a Deque
z modulu
collections
.
ChainMap
ChainMap
je datový typ, který nám umožňuje
sdružovat více slovníků do jednoho logického celku. Jinými slovy
nám ChainMap
umožňuje jednoduše a efektivně pracovat s
více slovníky jako s jedním.
ChainMap
se často používá v případě, když chceme hledat
hodnotu pro klíč ve více slovnících. Velkou výhodou
ChainMap
je, že nám umožňuje udržovat všechny slovníky v
jednom objektu. Hledání ve sdružených slovnících bude
probíhat postupně v pořadí, v jakém byly uvedeny při vytvoření instance,
dokud se pro klíč nenajde odpovídající hodnota.
Příklad použití
ChainMap
Použití ChainMap
v Pythonu je velmi jednoduché. Prvním
krokem je importovat modul collections
. Dále si nadefinujeme
slovníky slovnik1
a slovnik2
a poté vytvoříme
proměnnou mapa
, která bude obsahovat instanci třídy
ChainMap
:
from collections import ChainMap slovnik1 = {'a':1, 'b':2} slovnik2 = {'c':3, 'b':4} mapa = ChainMap(slovnik1, slovnik2)
Následně si vypíšeme obsah proměnné mapa
a na dalším
řádku výpis zopakujeme pro index ['b']
:
print(mapa) print(mapa['b'])
Výstupem v konzoli bude:
Konzolová aplikace
ChainMap({'a': 1, 'b': 2}, {'c': 3, 'b': 4})
2
Vidíme, že proměnná mapa
se chová jako slovník, ve kterém
jsou uloženy hodnoty ze slovnik1
a slovnik2
.
Následný výpis print(mapa['b'])
vrací hodnotu klíče
b
z prvního slovníku, ve kterém je k dispozici, tj. ze
slovnik1
.
Nyní si vyzkoušíme obsah proměnné mapa
modifikovat.
Přidáme řádek s kódem mapa['c'] = 5
. Tím přidáme do
proměnné mapa
nový klíč c
s hodnotou
5
. Tyto změny se projeví v proměnné mapa
,
ale ne v původních slovnících:
mapa['c'] = 5 print(mapa)
V konzoli tedy uvidíme:
Konzolová aplikace
ChainMap({'a': 1, 'b': 2, 'c': 5}, {'c': 3, 'b': 4})
Teď modifikujeme jeden ze slovníků a opět si vypíšeme obsah proměnné
mapa
:
slovnik2['c'] = 6 print(mapa)
Výstup v konzoli bude:
Konzolová aplikace
ChainMap({'a': 1, 'b': 2, 'c': 5}, {'c': 6, 'b': 4})
Vidíme, že hodnota klíče c
se v proměnné mapa
se změnila na 6
, protože se na 6
změnila i v
podkladovém slovníku (slovnik2['c'] = 6
).
Metody pro práci s
ChainMap
Třída ChainMap
obsahuje mimo jiné následující metody:
maps
- vrátí novou instanceChainMap
, která přidá zadaný slovník (nebo slovníky) na konec seznamu slovníků,new_child()
- přidá nový slovník na první pozici v seznamu,get(key[, default])
- vrátí hodnotu pro daný klíč. Pokud hodnota není nalezena, vrátí hodnotu default (pokud je zadána), jinak vyvolá výjimkuKeyError
,keys()
- vrátí seznam všech klíčů,values()
- vrátí seznam všech hodnot,items()
- vrátí seznam všech položek ve formátu (klíč, hodnota).
Výše uvedené si tedy shrneme. Platí, že ChainMap
je
aktualizovatelný pohled nad více slovníky. Hodnoty v
příslušné instanci se mění v závislosti na změnách v
jednotlivých podkladových slovnících.
NamedTuple
Třída NamedTuple
je speciální případ neseřazeného
datového typu, který kombinuje výhody tuple a slovníku. Stejně jako tuple
má také pevnou délku a její instance nelze modifikovat. Zásadní rozdíl
ale spočívá v tom, že jednotlivé položky mohou být přístupné pomocí
jména (stejně jako v případě slovníku).
Výhodou NamedTuple
tedy je, že umožňuje jasnější a
čitelnější kód, protože jména položek jsou přímo součástí kódu.
Díky pevné délce je také efektivnější než použití slovníku.
Příklad použití
NamedTuple
NamedTuple
se vytváří pomocí funkce
namedtuple()
. Nejprve si třídu NamedTuple
naimportujeme z modulu collections
. Poté pomocí funkce
namedtuple()
vytvoříme třídu Osoba
, která
rozšiřuje NamedTuple
o položky jmeno
,
prijmeni
a vek
. Následně vytvoříme proměnnou
student
, v níž bude instance třídy Osoba
:
from collections import namedtuple Osoba = namedtuple("Osoba", ["jmeno", "prijmeni", "vek"]) student = Osoba("Jan", "Novák", 26)
K položkám NamedTuple
pak budeme přistupovat pomocí jména
položky jako atributu instance, jako by šlo o obyčejné atributy třídy:
print("Jméno a příjmení studenta: "+ student.jmeno + " " + student.prijmeni) print("Věk studenta:", student.vek)
V konzoli vidíme výstup:
Konzolová aplikace
Jméno a příjmení studenta: Jan Novák
Věk studenta: 26
Následujícím způsobem pak vypíšeme celou instanci
NamedTuple
z proměnné turista
:
from collections import namedtuple Turista = namedtuple('Turista', ['jmeno', 'vek', 'zeme']) turista = Turista('Jan', 26, 'Norsko') print(turista)
Výstupem v konzoli bude:
Konzolová aplikace
Turista(jmeno='Jan', vek=26, zeme='Norsko')
Metody pro práci s
NamedTuple
Třída NamedTuple
obsahuje mimo jiné následující
metody:
make()
- umožňuje vytvořit instanciNamedTuple
z iterovatelných objektů jako jsou seznamy nebo sekvence,asdict()
- slouží k převodu na slovník,replace()
- vytvoří novou instanciNamedTuple
se stejným názvem, ale s novými hodnotami. Původní instanceNamedTuple
zůstává nezměněná,fields
- slouží k získání seznamu názvů všech položek v instanciNamedTuple
.
V praxi se NamedTuple
často používá jako výkonný a
jednoduchý způsob, jak organizovat a ukládat data, která spojuje nějaký
kontext, ale nejsou k nim třeba žádné další metody nebo funkce.
DeQue
Třída Deque
(zkratka pro "Double-Ended Queue") představuje
specifický typ fronty, který je implementovaný jako dvoustranně otevřený
seznam. To umožňuje efektivně přidávat a odebírat prvky z obou stran. V
praxi se DeQue
využívá například při řešení úloh s
BFS
(Breadth-First Search) a DFS
(Depth-First Search),
což jsou dva typy algoritmů pro hledání nejkratší cesty, hledání všech
cest, hledání komponent grafu apod.
Příklad použití DeQue
Použití DeQue
v Pythonu je velmi jednoduché. Prvním naším
krokem bude importovat modul collections
. Poté vytvoříme
instanci třídy DeQue
a vypíšeme si ji:
from collections import deque deq = deque([1,2,3,4]) print(deq)
Výstupem v konzoli bude:
Konzolová aplikace
deque([1, 2, 3, 4])
Vyzkoušejme si teď, jak funguje naše tvrzení o otevřených koncích
seznamu. Využijeme k tomu metody append()
,
appendleft()
, pop()
a popleft()
:
deq.append(5) print(deq) deq.appendleft(0) print(deq) deq.pop() print(deq) deq.popleft() print(deq)
V konzoli vidíme výsledek:
Konzolová aplikace
deque([1, 2, 3, 4])
deque([1, 2, 3, 4, 5])
deque([0, 1, 2, 3, 4, 5])
deque([0, 1, 2, 3, 4])
deque([1, 2, 3, 4])
Podívejme se teď blíže na to, co kód vykonal:
- nejprve jsme vytvořili frontu
deq
s prvky1
,2
,3
a4
, - pomocí metody
append()
jsme přidali prvek5
na konec fronty, - pomocí metody
appendleft()
jsme přidali prvek0
na začátek fronty, - pomocí metody
pop()
jsme odebrali poslední prvek z fronty, - pomocí metody
popleft()
jsme odebrali první prvek z fronty.
Metody pro práci s DeQue
Třída DeQue
obsahuje kromě už uvedených také
následující často využívané metody:
clear()
- smaže všechny prvky,count()
- vrátí počet výskytů určitého prvku,extend()
- přidá více prvků na konec,extendleft()
- přidá více prvků na začátek,remove()
- odstraní prvek s určitou hodnotou,reverse()
- otočí pořadí prvků.
Výhodou DeQue
oproti prostému seznamu je rychlost, protože
přidávání a odebírání prvků z obou stran je v ní implementováno
efektivně. Často se používá jako zásobník nebo fronta, do které lze
prvky na jednu stranu přidávat a z druhé strany je odebírat.
To by bylo pro tuto lekci vše.
V následujícím kvízu, Kvíz - Komprehence, Lambda, Chainmap a DeQue v Pythonu, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.