2.37. Named tuple e deque¶
Liste, tuple, dizionari e set coprono la maggior parte delle esigenze di gestione dei dati. Altri tre container nel modulo collections si adattano a problemi specifici che i tipi incorporati gestiscono in modo goffo.
2.37.1. namedtuple – record tipizzati senza una classe¶
Una tupla semplice memorizza i valori per posizione. Va bene per una piccola tupla di 2 o 3 elementi di breve durata, ma oltre quello point[0] e point[1] iniziano a mentire su cio che contengono. collections.namedtuple() restituisce una nuova sottoclasse di tupla i cui campi hanno dei nomi:
>>> 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
L’argomento fields e una sequenza di stringhe di nomi (oppure una singola stringa separata da spazi in CPython; MicroPython e piu rigoroso – passa una tupla o una lista).
Perche usare una namedtuple invece di una classe?
E una tupla. Iterazione, unpacking, uguaglianza, hashing e uso come chiave di un dict funzionano tutti gratuitamente.
E immutabile. Riassegnare
r.temp = ...sollevaAttributeError, che e esattamente cio che vuoi per un tipo record.Costa meno RAM di un’istanza di classe con gli stessi campi – lo spazio della tupla e contiguo, senza
__dict__.
Rispetto alla classe equivalente, una dichiarazione namedtuple e una sola riga. Il compromesso e che i campi sono di sola lettura – per «cambiare» una lettura ne crei una nuova.
2.37.2. deque – un ring buffer limitato¶
Una lista e veloce alla fine (append / pop) e lenta all”inizio (insert(0, ...) / pop(0) spostano entrambi ogni altro elemento). Una collections.deque e veloce a entrambe le estremita – e un ring buffer indicizzato da puntatori di testa e coda, quindi append e pop su entrambi i lati richiedono la stessa quantita fissa di lavoro indipendentemente da quanti elementi contiene la deque.
La costruzione in MicroPython richiede sia un iterabile iniziale sia una lunghezza massima, in quest’ordine:
>>> from collections import deque
>>> events = deque((), 5)
>>> for i in range(8):
... events.append(i)
>>> list(events)
[3, 4, 5, 6, 7]
Quando una deque limitata e piena, ogni append scarta l’elemento piu vecchio. Questo rende la deque ideale per «gli ultimi N campioni», «le ultime N righe di log» o qualsiasi finestra scorrevole che non deve crescere all’infinito.
I metodi esposti dalla deque di MicroPython sono volutamente minimali:
append(x)– aggiunge a destra.appendleft(x)– aggiunge a sinistra.extend(iterable)– aggiunge in coda ciascun elemento dell’iterabile.pop()– rimuove e restituisce l’estremita destra. SollevaIndexErrorse vuota.popleft()– rimuove e restituisce l’estremita sinistra.
Omissioni degne di nota rispetto alla deque di CPython: nessun clear, count, index, remove, reverse, rotate, attributo maxlen o __contains__. L’iterazione e l’indicizzazione con subscript funzionano:
>>> events[0]
3
>>> for e in events:
... print(e)
Un uso tipico: mantenere le ultime poche letture dei sensori per rilevare cambiamenti di tendenza:
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 – quando l’ordine fa parte dell’uguaglianza¶
Il normale dict preserva l’ordine di inserimento da MicroPython 1.13 e CPython 3.7. Questo copre il motivo piu comune per cui un tempo si ricorreva a collections.OrderedDict.
Cosa OrderedDict offre ancora che un dict semplice non offre:
L’uguaglianza di
OrderedDictconsidera l’ordine. Due dict normali risultano uguali ogni volta che hanno le stesse coppie chiave/valore, indipendentemente dall’ordine di inserimento. Due istanze diOrderedDictsono uguali solo se le loro coppie sono nello stesso ordine:>>> from collections import OrderedDict >>> OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)]) False >>> {'a': 1, 'b': 2} == {'b': 2, 'a': 1} True
OrderedDicte utile quando stai serializzando una configurazione in un formato che tiene conto dell’ordine delle chiavi (TOML, alcuni consumatori YAML), oppure quando vuoi un chiaro indizio documentale che l’ordine conta per chi legge il tuo codice.
Per il codice di tutti i giorni, preferisci il dict incorporato. Ricorri a OrderedDict solo quando la semantica dell’ordine-come-parte-dell’uguaglianza o il valore documentale offrono effettivamente qualcosa.
Ognuno dei tre container ha un’unica nicchia ristretta. Le named tuple sostituiscono le classi record fatte a mano; le deque sostituiscono le liste per le code limitate; gli ordered dict rendono l’ordine di inserimento parte del contratto.