2.37. Imenovane n-torke i dvostrani redovi

Liste, n-torke, rječnici i skupovi pokrivaju većinu potreba za podacima. Tri druga spremnika u modulu collections odgovaraju specifičnim problemima koje ugrađeni tipovi rješavaju nespretno.

2.37.1. namedtuple – tipizirani zapisi bez klase

Obična n-torka pohranjuje vrijednosti po poziciji. To je u redu za malu, kratkotrajnu n-torku s 2 ili 3 elementa, ali nakon toga point[0] i point[1] počinju lagati o tome što sadrže. collections.namedtuple() vraća novu podklasu n-torke čija polja imaju imena:

>>> from collections import namedtuple
>>> Reading = namedtuple('Reading', ('temp', 'humidity', 'ts'))
>>> r = Reading(22.5, 41.0, 137204)
>>> r.temp
22.5
>>> r.humidity
41.0
>>> r[0]
22.5

Argument polja je niz nizova imena (ili jedan niz razdvojen razmacima u CPythonu; MicroPython je stroži – proslijedite n-torku ili listu).

Zašto koristiti namedtuple umjesto klase?

  • To je n-torka. Iteracija, raspakiravanje, jednakost, raspršivanje i korištenje kao ključa rječnika – sve radi besplatno.

  • Nepromjenjiva je. Ponovno pridruživanje r.temp = ... podiže AttributeError, što je upravo ono što želite za tip zapisa.

  • Troši manje RAM-a nego instanca klase s istim poljima – pohrana n-torke je neprekinuta, bez __dict__.

U usporedbi s istovrijednom klasom, deklaracija namedtuple je jedan redak. Kompromis je u tome što su polja samo za čitanje – da biste „promijenili” očitanje, izrađujete novo.

2.37.2. deque – ograničeni prstenasti međuspremnik

Lista je brza na kraju (append / pop) i spora na početku (insert(0, ...) / pop(0) oboje pomiču svaki drugi element). collections.deque je brz na oba kraja – to je prstenasti međuspremnik indeksiran pokazivačima na glavu i rep, pa dodavanje i uklanjanje na bilo kojoj strani izvode istu fiksnu količinu posla bez obzira na to koliko stavki deque sadrži.

Konstrukcija u MicroPythonu zahtijeva i početni iterabilni objekt i maksimalnu duljinu, tim redoslijedom:

>>> from collections import deque
>>> events = deque((), 5)
>>> for i in range(8):
...     events.append(i)
>>> list(events)
[3, 4, 5, 6, 7]

Kada je ograničeni deque pun, svaki append izbacuje najstariju stavku. To čini deque idealnim za „posljednjih N uzoraka”, „posljednjih N redaka zapisnika” ili svaki klizni prozor koji ne treba rasti zauvijek.

Metode izložene na MicroPythonovom deque-u namjerno su minimalne:

  • append(x) – dodaj zdesna.

  • appendleft(x) – dodaj slijeva.

  • extend(iterable) – dodaj svaku stavku iz iterabilnog objekta.

  • pop() – ukloni i vrati desni kraj. Podiže IndexError kada je prazan.

  • popleft() – ukloni i vrati lijevi kraj.

Značajni izostanci iz CPythonovog deque-a: nema clear, count, index, remove, reverse, rotate, atributa maxlen ili __contains__. Iteracija i indeksiranje pretplaćivanjem rade:

>>> events[0]
3
>>> for e in events:
...     print(e)

Tipična upotreba: zadržavanje posljednjih nekoliko očitanja senzora radi otkrivanja promjena trenda:

history = deque((), 10)

def push(reading):
    history.append(reading)
    if len(history) == 10 and history[-1] > 2 * history[0]:
        print('reading is climbing')

2.37.3. OrderedDict – kada je redoslijed dio jednakosti

Obični dict čuva redoslijed umetanja od MicroPythona 1.13 i CPythona 3.7. To pokriva najčešći razlog zbog kojeg su ljudi nekoć posezali za collections.OrderedDict.

Što vam OrderedDict i dalje daje, a obični dict ne:

  • Jednakost kod OrderedDict uzima u obzir redoslijed. Dva obična rječnika uspoređuju se kao jednaki kad god imaju iste parove ključ/vrijednost, bez obzira na redoslijed umetanja. Dvije instance OrderedDict jednake su samo ako su im parovi istim redoslijedom:

    >>> from collections import OrderedDict
    >>> OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)])
    False
    >>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
    True
    
  • OrderedDict je koristan kada serijalizirate konfiguraciju u format kojemu jest stalo do redoslijeda ključeva (TOML, neki potrošači YAML-a) ili kada želite jasan dokumentacijski nagovještaj da je redoslijed bitan za čitatelje vašeg koda.

Za svakodnevni kod radije koristite ugrađeni dict. Posegnite za OrderedDict samo kada semantika redoslijed-je-dio-jednakosti ili dokumentacijska vrijednost stvarno nešto donosi.

Svaki od tri spremnika ima jednu usku namjenu. Imenovane n-torke zamjenjuju ručno izrađene klase zapisa; dvostrani redovi zamjenjuju liste za ograničene redove; uređeni rječnici čine redoslijed umetanja dijelom ugovora.