2.37. Named tuple-ök és deque-ek

A listák, tuple-ök, szótárak és halmazok a legtöbb adatigényt lefedik. A collections modul három további tárolója olyan konkrét problémákra való, amelyeket a beépített típusok ügyetlenül kezelnek.

2.37.1. namedtuple – típusos rekordok osztály nélkül

Egy egyszerű tuple pozíció szerint tárolja az értékeket. Ez rendben van egy kicsi, rövid életű 2- vagy 3-elemű tuple esetén, de azon túl a point[0] és a point[1] kezd hazudni arról, mit is tartalmaz. A collections.namedtuple() egy új tuple-alosztályt ad vissza, amelynek mezői névvel rendelkeznek:

>>> 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

A mezők argumentuma névsztringek sorozata (vagy egyetlen, szóközökkel elválasztott sztring CPythonban; a MicroPython szigorúbb – adj át egy tuple-t vagy listát).

Miért használjunk namedtuple típust osztály helyett?

  • Mert ez egy tuple. Az iteráció, a kicsomagolás, az egyenlőség, a hashelés és a szótárkulcsként való használat mind ingyen működik.

  • Mert megváltoztathatatlan. Az r.temp = ... újraértékadás AttributeError hibát vált ki, ami pontosan az, amit egy rekordtípusnál szeretnél.

  • Mert kevesebb RAM-ba kerül, mint egy ugyanolyan mezőkkel rendelkező osztálypéldány – a tuple tárolása összefüggő, __dict__ nélkül.

Az egyenértékű osztállyal összehasonlítva egy namedtuple deklaráció egyetlen sor. A kompromisszum az, hogy a mezők csak olvashatók – egy leolvasás „megváltoztatásához” újat hozol létre.

2.37.2. deque – korlátos gyűrűpuffer

Egy lista a végén gyors (append / pop), az elején pedig lassú (az insert(0, ...) és a pop(0) is minden további elemet eltol). A collections.deque mindkét végén gyors – ez egy fej- és farokmutatóval indexelt gyűrűpuffer, így bármelyik oldalon az append és a pop azonos, rögzített mennyiségű munkával fut, függetlenül attól, hány elemet tart a deque.

A MicroPythonban a létrehozás egyszerre igényel egy kezdeti iterálhatót és egy maximális hosszt, ebben a sorrendben:

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

Amikor egy korlátos deque megtelik, minden append eldobja a legrégebbi elemet. Ez teszi a deque-et ideálissá „az utolsó N minta”, „az utolsó N naplósor” vagy bármilyen gördülő ablak esetén, amelynek nem kell örökké nőnie.

A MicroPython deque-én elérhető metódusok szándékosan minimálisak:

  • append(x) – hozzáadás a jobb oldalhoz.

  • appendleft(x) – hozzáadás a bal oldalhoz.

  • extend(iterable) – az iterálható minden elemének hozzáfűzése.

  • pop() – a jobb vég eltávolítása és visszaadása. Üres deque esetén IndexError hibát vált ki.

  • popleft() – a bal vég eltávolítása és visszaadása.

Figyelemre méltó hiányosságok a CPython deque-éhez képest: nincs clear, count, index, remove, reverse, rotate, maxlen attribútum vagy __contains__. Az iteráció és az indexeléses elérés működik:

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

Egy tipikus felhasználás: az utolsó néhány érzékelő-leolvasás megtartása a trendváltozások észleléséhez:

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 – amikor a sorrend az egyenlőség része

A szokásos dict a MicroPython 1.13 és a CPython 3.7 óta megőrzi a beszúrási sorrendet. Ez lefedi a leggyakoribb okot, amiért az emberek korábban a collections.OrderedDict után nyúltak.

Amit az OrderedDict még mindig nyújt, amit egy egyszerű szótár nem:

  • Az OrderedDict egyenlősége figyelembe veszi a sorrendet. Két szokásos szótár egyenlőnek számít, valahányszor ugyanazok a kulcs/érték párjaik, a beszúrási sorrendtől függetlenül. Két OrderedDict példány csak akkor egyenlő, ha a párjaik azonos sorrendben vannak:

    >>> from collections import OrderedDict
    >>> OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)])
    False
    >>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1}
    True
    
  • Az OrderedDict akkor hasznos, amikor olyan formátumba sorosítod a konfigurációt, amely törődik a kulcsok sorrendjével (TOML, egyes YAML-feldolgozók), vagy amikor egyértelmű dokumentációs jelzést szeretnél adni arról, hogy a sorrend számít a kódod olvasói számára.

A hétköznapi kódhoz inkább a beépített dict típust részesítsd előnyben. Az OrderedDict után csak akkor nyúlj, amikor a sorrend-az-egyenlőség-része szemantika vagy a dokumentációs érték tényleg ad valamit.

A három tároló mindegyikének egy-egy szűk felhasználási területe van. A named tuple-ök kiváltják a kézzel írt rekordosztályokat; a deque-ek kiváltják a listákat korlátos sorok esetén; a rendezett szótárak pedig a beszúrási sorrendet a megállapodás részévé teszik.