2.37. Tuplas nomeadas e deques¶
Listas, tuplas, dicionários e conjuntos cobrem a maioria das necessidades de dados. Três outros contêineres no módulo collections se ajustam a problemas específicos que os tipos embutidos tratam de forma desajeitada.
2.37.1. namedtuple – registros tipados sem uma classe¶
Uma tupla simples armazena valores por posição. Isso é adequado para uma 2- ou 3-tupla pequena e de vida curta, mas além disso point[0] e point[1] começam a mentir sobre o que contêm. collections.namedtuple() retorna uma nova subclasse de tupla cujos campos têm nomes:
>>> 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
O argumento de campos é uma sequência de strings de nome (ou uma única string separada por espaços em branco no CPython; o MicroPython é mais estrito – passe uma tupla ou lista).
Por que usar uma namedtuple em vez de uma classe?
É uma tupla. Iteração, desempacotamento, igualdade, hashing e uso como chave de dicionário funcionam de graça.
É imutável. Reatribuir
r.temp = ...levantaAttributeError, que é exatamente o que você quer para um tipo de registro.Custa menos RAM que uma instância de classe com os mesmos campos – o armazenamento da tupla é contíguo, sem
__dict__.
Comparada com a classe equivalente, uma declaração de namedtuple é uma linha. A contrapartida é que os campos são somente leitura – para “mudar” uma leitura você cria uma nova.
2.37.2. deque – um ring buffer limitado¶
Uma lista é rápida no fim (append / pop) e lenta no início (insert(0, ...) / pop(0) ambos deslocam todos os outros elementos). Uma collections.deque é rápida em ambas as extremidades – é um ring buffer indexado por ponteiros de cabeça e cauda, então append e pop em qualquer um dos lados executam a mesma quantidade fixa de trabalho, independentemente de quantos itens a deque contém.
A construção no MicroPython requer tanto um iterável inicial quanto um comprimento máximo, nessa ordem:
>>> from collections import deque
>>> events = deque((), 5)
>>> for i in range(8):
... events.append(i)
>>> list(events)
[3, 4, 5, 6, 7]
Quando uma deque limitada está cheia, cada append descarta o item mais antigo. Isso torna a deque ideal para “as últimas N amostras”, “as últimas N linhas de log” ou qualquer janela deslizante que não precise crescer para sempre.
Os métodos expostos na deque do MicroPython são deliberadamente mínimos:
append(x)– adiciona à direita.appendleft(x)– adiciona à esquerda.extend(iterable)– anexa cada item do iterável.pop()– remove e retorna a extremidade direita. LevantaIndexErrorse estiver vazia.popleft()– remove e retorna a extremidade esquerda.
Omissões notáveis em relação à deque do CPython: sem clear, count, index, remove, reverse, rotate, atributo maxlen ou __contains__. Iteração e indexação por subscrito funcionam:
>>> events[0]
3
>>> for e in events:
... print(e)
Um uso típico: manter as últimas leituras de sensor para detectar mudanças de tendência:
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 a ordem faz parte da igualdade¶
O dict regular preserva a ordem de inserção desde o MicroPython 1.13 e o CPython 3.7. Isso cobre o motivo mais comum pelo qual as pessoas costumavam recorrer a collections.OrderedDict.
O que OrderedDict ainda oferece que um dict simples não oferece:
A igualdade de
OrderedDictconsidera a ordem. Dois dicts regulares comparam como iguais sempre que têm os mesmos pares chave/valor, independentemente da ordem de inserção. Duas instâncias deOrderedDictsão iguais somente se seus pares estiverem na mesma ordem:>>> 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é útil quando você está serializando configuração para um formato que de fato se importa com a ordem das chaves (TOML, alguns consumidores de YAML), ou quando você quer uma dica clara de documentação de que a ordem importa para quem lê seu código.
Para código do dia a dia, prefira o dict embutido. Recorra a OrderedDict apenas quando a semântica de ordem-faz-parte-da-igualdade ou o valor documental realmente trouxer algo.
Cada um dos três contêineres tem um encaixe estreito. Tuplas nomeadas substituem classes de registro feitas à mão; deques substituem listas para filas limitadas; dicts ordenados tornam a ordem de inserção parte do contrato.