2.37. Namngivna tupler och deques¶
Listor, tupler, ordlistor och mängder täcker de flesta databehoven. Tre andra behållare i modulen collections passar specifika problem som de inbyggda hanterar klumpigt.
2.37.1. namedtuple – typade poster utan en klass¶
En vanlig tupel lagrar värden efter position. Det är fint för en liten, kortlivad 2- eller 3-tupel, men därefter börjar point[0] och point[1] ljuga om vad de innehåller. collections.namedtuple() returnerar en ny tupelunderklass vars fält har namn:
>>> 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
Fältargumentet är en sekvens av namnsträngar (eller en mellanslagsseparerad sträng i CPython; MicroPython är striktare – skicka en tupel eller lista).
Varför använda en namedtuple i stället för en klass?
Det är en tupel. Iteration, uppackning, likhet, hashning och användning som ordlistenyckel fungerar gratis.
Den är oföränderlig. Att tilldela om
r.temp = ...ger upphov tillAttributeError, vilket är precis vad du vill ha för en posttyp.Den kostar mindre RAM än en klassinstans med samma fält – tupelns lagring är sammanhängande, utan något
__dict__.
Jämfört med den motsvarande klassen är en namedtuple-deklaration en rad. Avvägningen är att fälten är skrivskyddade – för att ”ändra” en avläsning skapar du en ny.
2.37.2. deque – en begränsad ringbuffert¶
En lista är snabb i slutet (append / pop) och långsam i början (insert(0, ...) / pop(0) förskjuter båda varje annat element). En collections.deque är snabb i båda ändar – det är en ringbuffert indexerad av huvud- och svanspekare, så append och pop på endera sidan utför samma fasta mängd arbete oavsett hur många objekt deque:n innehåller.
Konstruktion i MicroPython kräver både en initial iterabel och en maxlängd, i den ordningen:
>>> from collections import deque
>>> events = deque((), 5)
>>> for i in range(8):
... events.append(i)
>>> list(events)
[3, 4, 5, 6, 7]
När en begränsad deque är full släpper varje append det äldsta objektet. Det gör deque:n idealisk för ”de senaste N proverna”, ”de senaste N loggraderna” eller vilket rullande fönster som helst som inte behöver växa för evigt.
Metoderna som exponeras på MicroPythons deque är medvetet minimala:
append(x)– lägg till till höger.appendleft(x)– lägg till till vänster.extend(iterable)– lägg till varje objekt från iterabeln.pop()– ta bort och returnera höger ände. Ger upphov tillIndexErrornär den är tom.popleft()– ta bort och returnera vänster ände.
Anmärkningsvärda utelämnanden från CPythons deque: inget clear, count, index, remove, reverse, rotate, maxlen-attribut eller __contains__. Iteration och indexering med subskript fungerar:
>>> events[0]
3
>>> for e in events:
... print(e)
En typisk användning: att behålla de senaste sensoravläsningarna för att upptäcka trendförändringar:
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 – när ordning är en del av likhet¶
Vanlig dict har bevarat infogningsordning sedan MicroPython 1.13 och CPython 3.7. Det täcker den vanligaste anledningen till att folk förr grep efter collections.OrderedDict.
Vad OrderedDict fortfarande ger dig som en vanlig dict inte gör:
OrderedDict-likhet beaktar ordning. Två vanliga dicts jämförs som lika närhelst de har samma nyckel/värde-par, oavsett infogningsordning. TvåOrderedDict-instanser är lika endast om deras par är i samma ordning:>>> 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är användbar när du serialiserar konfiguration till ett format som bryr sig om nyckelordning (TOML, vissa YAML-konsumenter), eller när du vill ge en tydlig dokumentationsantydan om att ordning spelar roll för läsarna av din kod.
För vardaglig kod, föredra den inbyggda dict. Grip efter OrderedDict endast när semantiken att ordning är en del av likhet eller det dokumentariska värdet faktiskt ger något.
De tre behållarna har var och en en smal nisch. Namngivna tupler ersätter handskrivna postklasser; deques ersätter listor för begränsade köer; ordnade dicts gör infogningsordning till en del av kontraktet.