O módulo collections da biblioteca padrão do Python é um dos conjuntos de ferramentas mais valiosos para qualquer desenvolvedor. Ele oferece tipos de dados especializados que vão além dos tipos nativos como listas, tuplas e dicionários, resolvendo problemas comuns de forma elegante e eficiente. De acordo com a documentação oficial do Python para collections, este módulo implementa containers de dados alternativos com características específicas para diferentes cenários.

Se você já precisou contar elementos de uma lista, criar uma fila eficiente ou acessar múltiplos dicionários como se fossem um só, o módulo collections tem a solução ideal. Ele complementa perfeitamente os dicionários em Python e as tuplas e conjuntos em Python, que são estruturas fundamentais da linguagem. Neste guia completo, você aprenderá cada um dos principais componentes do módulo collections com exemplos práticos e casos de uso reais.

O que é o módulo collections?

O módulo collections foi introduzido na versão 2.4 do Python e expandido significativamente ao longo dos anos. Ele fornece alternativas aos tipos de dados nativos para situações onde listas, tuplas e dicionários comuns não são suficientes ou não são eficientes. Cada classe do módulo resolve um problema específico: manter a ordem de inserção, fornecer valores padrão para chaves ausentes, criar objetos leves similares a tuplas com campos nomeados, entre outros.

A documentação da Real Python sobre collections oferece uma excelente introdução aos conceitos fundamentais, classificando cada estrutura de dados de acordo com seu caso de uso ideal. O módulo é puramente implementado em Python, com otimizações em C para máxima performance, como você pode conferir no código-fonte oficial do CPython no GitHub.

Counter: contando elementos como um profissional

A classe Counter é uma subclasse de dict projetada especificamente para contar objetos hasháveis. Ela armazena os elementos como chaves e suas contagens como valores, tornando trivial responder perguntas como "qual palavra aparece com mais frequência neste texto?" ou "quantas vezes este número aparece na lista?".

Criando e usando um Counter

from collections import Counter

A partir de uma lista

frutas = ['maçã', 'banana', 'maçã', 'laranja', 'banana', 'maçã'] contador = Counter(frutas) print(contador)

Counter({'maçã': 3, 'banana': 2, 'laranja': 1})

A partir de uma string

letras = Counter("paralelepipedo") print(letras)

Counter({'p': 3, 'e': 3, 'a': 2, 'l': 2, 'r': 1, 'i': 1, 'd': 1, 'o': 1})

A partir de um dicionário

contador = Counter({'a': 4, 'b': 2, 'c': 1})

Métodos essenciais do Counter

O Counter oferece métodos que vão muito além da simples contagem. O método most_common() retorna os n elementos mais frequentes, ideal para rankings:

from collections import Counter

vendas = Counter(['iphone', 'iphone', 'samsung', 'iphone', 'xiaomi', 'samsung']) print(vendas.most_common(2))

[('iphone', 3), ('samsung', 2)]

Operações aritméticas entre Counters são suportadas naturalmente:

c1 = Counter(a=3, b=1, c=2)
c2 = Counter(a=1, b=2, c=3)

print(c1 + c2) # Soma: Counter({'c': 5, 'a': 4, 'b': 3}) print(c1 - c2) # Subtração: Counter({'a': 2}) (apenas positivos) print(c1 & c2) # Interseção (mínimo): Counter({'a': 1, 'b': 1, 'c': 2}) print(c1 | c2) # União (máximo): Counter({'c': 3, 'a': 3, 'b': 2})

A classe Counter é amplamente utilizada em processamento de linguagem natural, análise de logs, e qualquer cenário que exija contagem de frequência. Consulte a documentação oficial sobre objetos Counter para detalhes completos da API.

defaultdict: dicionários com valores padrão

Quantas vezes você escreveu um código como este?

dicionario = {}
for chave, valor in dados:
    if chave not in dicionario:
        dicionario[chave] = []
    dicionario[chave].append(valor)

O defaultdict elimina essa repetição. Ele é uma subclasse de dict que chama uma função factory para fornecer valores padrão quando uma chave inexistente é acessada:

from collections import defaultdict

defaultdict com list como factory

dados = [('a', 1), ('b', 2), ('a', 3), ('c', 4), ('b', 5)] dd = defaultdict(list) for chave, valor in dados: dd[chave].append(valor)

print(dict(dd))

{'a': [1, 3], 'b': [2, 5], 'c': [4]}

Usos comuns do defaultdict

As factories mais utilizadas com defaultdict são list, set, int e dict:

from collections import defaultdict

defaultdict(int) para contagem automática

contagem = defaultdict(int) for palavra in ["um", "dois", "um", "tres", "um", "dois"]: contagem[palavra] += 1 print(dict(contagem))

{'um': 3, 'dois': 2, 'tres': 1}

defaultdict(set) para conjuntos

agrupamento = defaultdict(set) agrupamento['pares'].add(2) agrupamento['pares'].add(4) agrupamento['impares'].add(1) print(dict(agrupamento))

{'pares': {2, 4}, 'impares': {1}}

defaultdict(dict) para dicionários aninhados

aninhado = defaultdict(dict) aninhado['user1']['nome'] = 'Alice' aninhado['user2']['nome'] = 'Bob' print(dict(aninhado))

{'user1': {'nome': 'Alice'}, 'user2': {'nome': 'Bob'}}

O defaultdict é especialmente útil ao processar dados agrupados e construir estruturas aninhadas. Veja a documentação oficial sobre defaultdict para mais exemplos e casos de uso avançados.

namedtuple: tuplas com nomes de campos

A função namedtuple() cria classes de tupla cujos campos podem ser acessados tanto por índice quanto por nome. Isso combina a imutabilidade e eficiência das tuplas com a legibilidade dos dicionários:

from collections import namedtuple

Definindo uma namedtuple

Ponto = namedtuple('Ponto', ['x', 'y']) p1 = Ponto(10, 20) p2 = Ponto(x=30, y=40)

print(p1.x, p1.y) # 10 20 (acesso por nome) print(p2[0], p2[1]) # 30 40 (acesso por índice)

Sua representação é limpa

print(p1) # Ponto(x=10, y=20)

Namedtuples em aplicações reais

Namedtuples são ideais para representar registros leves sem a sobrecarga de uma classe completa. Elas são imutáveis, consomem menos memória que dicionários e são mais legíveis que tuplas comuns:

from collections import namedtuple

Registro de funcionário

Funcionario = namedtuple('Funcionario', ['id', 'nome', 'cargo', 'salario'])

funcs = [ Funcionario(1, 'Ana Silva', 'Engenheira de Dados', 12000), Funcionario(2, 'Carlos Souza', 'Cientista de Dados', 15000), Funcionario(3, 'Maria Lima', 'Desenvolvedora Python', 10000), ]

Filtrar com comprensão de lista

engenheiros = [f for f in funcs if 'Dados' in f.cargo] print(engenheiros[0].nome) # Ana Silva

Além dos campos nomeados, a namedtuple oferece o método _asdict() para converter em dicionário e _replace() para criar uma nova instância com campos alterados:

p = Ponto(10, 20)
print(p._asdict())   # {'x': 10, 'y': 20}
p2 = p._replace(x=50)
print(p2)            # Ponto(x=50, y=20)

Segundo a documentação oficial sobre namedtuple, esta função é especialmente útil para substituir tuplas comuns quando a legibilidade do código é importante.

deque: filas e pilhas eficientes

A classe deque (double-ended queue) é uma lista otimizada para inserções e remoções em ambas as extremidades. Enquanto uma lista Python tem complexidade O(n) para inserir ou remover no início, o deque oferece O(1) para essas operações:

from collections import deque

Criando um deque

fila = deque(['a', 'b', 'c'])

Adicionar no final

fila.append('d') print(fila) # deque(['a', 'b', 'c', 'd'])

Adicionar no início

fila.appendleft('z') print(fila) # deque(['z', 'a', 'b', 'c', 'd'])

Remover do final

ultimo = fila.pop() print(ultimo) # d

Remover do início

primeiro = fila.popleft() print(primeiro) # z

Rotacionando e limitando o deque

O deque oferece duas funcionalidades poderosas: rotação e tamanho máximo:

from collections import deque

Rotação (útil para jogos e algoritmos circulares)

d = deque([1, 2, 3, 4, 5]) d.rotate(2) print(d) # deque([4, 5, 1, 2, 3]) d.rotate(-1) print(d) # deque([5, 1, 2, 3, 4])

Tamanho máximo (buffer circular automático)

buffer = deque(maxlen=3) buffer.append(1) buffer.append(2) buffer.append(3) print(buffer) # deque([1, 2, 3], maxlen=3) buffer.append(4) # Remove automaticamente o elemento mais antigo print(buffer) # deque([2, 3, 4], maxlen=3)

O deque é a estrutura ideal para implementar filas de tarefas, histórico de navegação (com maxlen), buffers circulares e algoritmos de sliding window. Consulte a documentação oficial sobre objetos deque para uma visão completa de todos os métodos disponíveis.

OrderedDict: dicionários com ordem garantida

Antes do Python 3.7, os dicionários comuns não garantiam ordem de inserção. O OrderedDict foi criado para preencher essa lacuna. Hoje, com dicionários nativos ordenados, seu principal diferencial é o método move_to_end():

from collections import OrderedDict

od = OrderedDict() od['a'] = 1 od['b'] = 2 od['c'] = 3 od['d'] = 4

Move a chave 'a' para o final

od.move_to_end('a') print(od)

OrderedDict([('b', 2), ('c', 3), ('d', 4), ('a', 1)])

Move 'd' para o início

od.move_to_end('d', last=False) print(od)

OrderedDict([('d', 4), ('b', 2), ('c', 3), ('a', 1)])

Além disso, o OrderedDict considera a ordem ao comparar igualdade, ao contrário dos dicionários comuns:

from collections import OrderedDict

od1 = OrderedDict([('a', 1), ('b', 2)]) od2 = OrderedDict([('b', 2), ('a', 1)])

print(od1 == od2) # False (a ordem importa!)

dict1 = {'a': 1, 'b': 2} dict2 = {'b': 2, 'a': 1} print(dict1 == dict2) # True (ordem não importa)

O OrderedDict é ideal para implementar caches LRU (Least Recently Used) e qualquer estrutura que precise manter registro de ordem de acesso ou inserção. Veja a documentação oficial sobre OrderedDict para mais detalhes e exemplos.

ChainMap: múltiplos dicionários em um só

A classe ChainMap agrupa múltiplos dicionários ou mapeamentos em uma única visão pesquisável. As buscas percorrem os dicionários na ordem em que foram passados, retornando o primeiro valor encontrado:

from collections import ChainMap

Configurações com precedência

padroes = {'tema': 'claro', 'idioma': 'pt-BR', 'notificacoes': True} usuario = {'idioma': 'en-US', 'notificacoes': False} ambiente = {'tema': 'escuro'}

config = ChainMap(ambiente, usuario, padroes)

print(config['tema']) # 'escuro' (vem de ambiente) print(config['idioma']) # 'en-US' (vem de usuario) print(config['notificacoes']) # False (vem de usuario)

Atualizações afetam apenas o primeiro dicionário

config['tema'] = 'contraste' print(ambiente['tema']) # 'contraste'

O ChainMap é extremamente útil para gerenciar configurações com diferentes níveis de precedência (padrão → usuário → ambiente), processamento de argumentos de linha de comando combinados com defaults, e escopos de variáveis em interpretadores:

from collections import ChainMap

Escopo de variáveis simulando um interpretador

global_scope = {'x': 10, 'y': 20, 'nome': 'global'} local_scope = {'x': 5, 'z': 30}

scope = ChainMap(local_scope, global_scope) print(scope['x']) # 5 (local) print(scope['y']) # 20 (global) print(scope['z']) # 30 (local)

Adicionar novo escopo

scope = scope.new_child({'x': 1, 'w': 100}) print(scope['x']) # 1 (novo escopo local)

De acordo com a documentação oficial sobre ChainMap, esta classe é particularmente útil quando você precisa gerenciar múltiplos namespaces sem mesclá-los.

Outras ferramentas do módulo collections

Além das classes principais, o módulo collections oferece outras ferramentas valiosas:

UserDict, UserList e UserString

Estas classes são wrappers que facilitam a criação de subclasses de dict, list e string. Diferente de herdar diretamente desses tipos nativos, essas classes expõem atributos como .data para acesso ao conteúdo interno, simplificando a personalização:

from collections import UserDict

class DicionarioMinusculo(UserDict): def setitem(self, chave, valor): chave = chave.lower() super().setitem(chave, valor)

d = DicionarioMinusculo() d['Nome'] = 'Alice' print(d.data) # {'nome': 'Alice'}

Boas práticas com collections

Para tirar o máximo proveito do módulo collections, considere as seguintes recomendações:

  • Use Counter em vez de implementar sua própria lógica de contagem com dicionários — o código fica mais legível e eficiente
  • Prefira defaultdict sempre que precisar verificar se uma chave existe antes de acessá-la; isso elimina blocos if chave in dict repetitivos
  • Escolha namedtuple sobre tuplas comuns quando os dados têm significado semântico; seu código se torna autodocumentado
  • Utilize deque para filas e pilhas em vez de listas quando houver operações frequentes no início da coleção
  • Recorra a OrderedDict quando a ordem de inserção importar para a lógica do seu algoritmo
  • Adote ChainMap para gerenciar configurações com múltiplas camadas de precedência sem mesclar dicionários

Performance: collections vs tipos nativos

Um aspecto frequentemente subestimado é o ganho de performance ao usar as classes certas do módulo collections. Veja uma comparação prática:

from collections import deque, Counter, defaultdict
import time

deque vs list para inserção no início

n = 100000

lista = [] inicio = time.time() for i in range(n): lista.insert(0, i) print(f"list.insert(0): {time.time() - inicio:.3f}s")

deq = deque() inicio = time.time() for i in range(n): deq.appendleft(i) print(f"deque.appendleft: {time.time() - inicio:.3f}s")

Resultado típico: deque é 100x mais rápido

O módulo collections implementa cada classe com a estrutura de dados mais adequada para seu propósito. O deque, por exemplo, é implementado como um array de blocos fixos (double-ended queue), enquanto o Counter herda a implementação otimizada em C do dict nativo. Para benchmarks detalhados, consulte o guia de performance da documentação oficial.

Conclusão

O módulo collections é uma das bibliotecas mais úteis da stdlib do Python. Ele fornece soluções elegantes e eficientes para problemas recorrentes de programação: contagem de frequência com Counter, valores padrão com defaultdict, registros nomeados com namedtuple, filas eficientes com deque, ordem garantida com OrderedDict e escopos encadeados com ChainMap.

Dominar essas ferramentas não apenas torna seu código mais limpo e legível, mas também melhora significativamente a performance das suas aplicações. Cada classe foi projetada para um conjunto específico de problemas, e saber qual escolher é uma marca de um desenvolvedor Python experiente.

Para continuar seus estudos, explore a documentação oficial completa do módulo collections e pratique implementando os exemplos deste guia em seus próprios projetos. O conhecimento aprofundado das ferramentas padrão do Python é um dos maiores diferenciais de um programador eficiente.