2.37. Pojmenované n-tice a deque

Seznamy, n-tice, slovníky a množiny pokrývají většinu datových potřeb. Tři další kontejnery v modulu collections se hodí na specifické problémy, které vestavěné typy zvládají neobratně.

2.37.1. namedtuple – typované záznamy bez třídy

Obyčejná n-tice ukládá hodnoty podle pozice. To je v pořádku pro malou, krátce žijící 2- nebo 3-tici, ale dále už point[0] a point[1] začínají zastírat, co obsahují. collections.namedtuple() vrací novou podtřídu n-tice, jejíž pole mají jména:

>>> 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 fields je sekvence řetězců s názvy (nebo v CPythonu jeden řetězec oddělený mezerami; MicroPython je přísnější – předejte n-tici nebo seznam).

Proč použít namedtuple namísto třídy?

  • Je to n-tice. Iterace, rozbalení, rovnost, hashování a použití jako klíč slovníku fungují zdarma.

  • Je neměnná. Přiřazení r.temp = ... vyvolá AttributeError, což je přesně to, co u typu záznamu chcete.

  • Stojí méně RAM než instance třídy se stejnými poli – úložiště n-tice je souvislé, bez __dict__.

Ve srovnání s ekvivalentní třídou je deklarace namedtuple jeden řádek. Kompromisem je, že pole jsou pouze pro čtení – abyste „změnili“ hodnotu, vytvoříte novou.

2.37.2. deque – ohraničený kruhový buffer

Seznam je rychlý na konci (append / pop) a pomalý na začátku (insert(0, ...) / pop(0) oba posunou každý další prvek). collections.deque je rychlá na obou koncích – je to kruhový buffer indexovaný ukazateli na hlavu a ocas, takže append a pop na kterékoli straně proběhnou se stejným pevným množstvím práce bez ohledu na to, kolik položek deque obsahuje.

Konstrukce v MicroPythonu vyžaduje jak počáteční iterovatelný objekt, tak maximální délku, v tomto pořadí:

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

Když je ohraničená deque plná, každý append zahodí nejstarší položku. To činí z deque ideální volbu pro „posledních N vzorků“, „posledních N řádků logu“ nebo libovolné klouzavé okno, které nemusí růst donekonečna.

Metody vystavené na deque v MicroPythonu jsou záměrně minimální:

  • append(x) – přidá doprava.

  • appendleft(x) – přidá doleva.

  • extend(iterable) – připojí každou položku z iterovatelného objektu.

  • pop() – odebere a vrátí pravý konec. Na prázdné vyvolá IndexError.

  • popleft() – odebere a vrátí levý konec.

Pozoruhodné nedostatky oproti deque z CPythonu: žádné clear, count, index, remove, reverse, rotate, atribut maxlen ani __contains__. Iterace a indexování přes index fungují:

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

Typické použití: udržování posledních několika hodnot senzoru pro detekci změn trendu:

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 – když je pořadí součástí rovnosti

Běžný dict zachovává pořadí vkládání od MicroPythonu 1.13 a CPythonu 3.7. To pokrývá nejčastější důvod, proč lidé dříve sahali po collections.OrderedDict.

Co vám OrderedDict stále poskytuje oproti obyčejnému slovníku:

  • Rovnost OrderedDict bere v úvahu pořadí. Dva běžné slovníky se porovnají jako rovné, kdykoli mají stejné dvojice klíč/hodnota, bez ohledu na pořadí vkládání. Dvě instance OrderedDict jsou rovné pouze tehdy, jsou-li jejich dvojice ve stejném pořadí:

    >>> 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 užitečný, když serializujete konfiguraci do formátu, kterému záleží na pořadí klíčů (TOML, někteří konzumenti YAML), nebo když chcete čtenářům svého kódu jasně dokumentačně naznačit, že na pořadí záleží.

Pro běžný kód dejte přednost vestavěnému dict. Po OrderedDict sáhněte jen tehdy, když sémantika „pořadí je součástí rovnosti“ nebo dokumentační hodnota skutečně něco přinese.

Každý z těchto tří kontejnerů má jedno úzké uplatnění. Pojmenované n-tice nahrazují ručně psané třídy záznamů; deque nahrazují seznamy pro ohraničené fronty; uspořádané slovníky činí pořadí vkládání součástí kontraktu.