Módulo collections
El módulo collections extiende los contenedores integrados con tipos especializados optimizados para patrones comunes: agrupación, conteo, colas de doble extremo y configuración en capas.
Receta
from collections import Counter, defaultdict, deque
words = Counter("abracadabra".split())
by_len: defaultdict[int, list[str]] = defaultdict(list)
queue: deque[str] = deque(maxlen=100)Cuándo recurrir a esto:
- Agrupar elementos por clave sin
if key not in dict - Análisis de frecuencia y recuentos de los N principales
- Colas BFS y búferes rodantes
- Superposiciones de configuración apiladas con
ChainMap
Ejemplo práctico
from collections import ChainMap, Counter, defaultdict, deque
def group_by(items: list[dict], field: str) -> dict[str, list[dict]]:
groups: defaultdict[str, list[dict]] = defaultdict(list)
for item in items:
groups[str(item[field])].append(item)
return dict(groups)
def top_n_words(text: str, n: int) -> list[tuple[str, int]]:
counts = Counter(word.lower() for word in text.split())
return counts.most_common(n)
def sliding_window(values: list[int], size: int) -> list[int]:
window: deque[int] = deque(maxlen=size)
sums: list[int] = []
for v in values:
window.append(v)
if len(window) == size:
sums.append(sum(window))
return sums
def merged_config(*maps: dict[str, object]) -> ChainMap:
return ChainMap(*maps)
if __name__ == "__main__":
rows = [{"role": "dev", "name": "a"}, {"role": "dev", "name": "b"}]
print(group_by(rows, "role"))
print(top_n_words("a b a c a b", 2))
print(sliding_window([1, 2, 3, 4, 5], 3))Lo que esto demuestra:
defaultdict(list)añade sin comprobaciones de existenciaCounter.most_commondevuelve pares clasificadosdeque(maxlen=...)elimina automáticamente los elementos más antiguos para ventanas rodantesChainMapbusca en la pila de diccionarios la primera clave coincidente
Análisis en profundidad
Cómo funciona
- defaultdict - Subclase de dict; llamable de fábrica en
__missing__. - Counter - Subclase de dict; las claves faltantes devuelven 0; admite
+,-,&,|. - deque - Bloques enlazados doblemente;
append/popO(1) en ambos extremos. - OrderedDict - Históricamente un dict ordenado; ahora en su mayoría obsoleto excepto
move_to_end. - ChainMap - Superposición no destructiva; las escrituras van solo al primer mapa.
Elige el tipo correcto
| Tipo | Uso |
|---|---|
deque | Cola, pila, ventana rodante |
Counter | Recuentos de palabras, histogramas |
defaultdict | Agrupación por, listas de adyacencia |
ChainMap | Capas de configuración con ámbito |
Notas de Python
# Counter como multiconjunto
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, c=2)
print(c1 + c2)
# move_to_end en OrderedDict para ordenamiento tipo LRUErrores comunes
- Efectos secundarios de la fábrica de
defaultdict- La fábrica solo se llama en claves faltantes; aún así, evita trabajo pesado en la fábrica. Solución: Usalist,int,setsimples. - Recuentos negativos de
Counter- Permitidos pero confusos. Solución: Usasubtractconscientemente o filtra los positivos. dequemaxlenomisión silenciosa - Los elementos más antiguos desaparecen sin error. Solución: Documenta el comportamiento o comprueba la longitud.- Sorpresas de escritura de
ChainMap- Las actualizaciones solo afectan al primer dict. Solución: Copia el resultado fusionado si necesitas un dict plano. OrderedDictpara el orden - Los dict normales ya están ordenados. Solución: UsaOrderedDictsolo para patrones LRU demove_to_end.
Alternativas
| Alternativa | Úsala cuando | No la uses cuando |
|---|---|---|
dict normal | Mapas simples | Boilerplate repetitivo de claves faltantes |
pandas.value_counts | Columnas de DataFrame | Script solo con la biblioteca estándar |
heapq | Ordenamiento por prioridad | Solo cola FIFO |
functools.lru_cache | Memoización de funciones | Conteo de iterables arbitrarios |
Preguntas frecuentes
¿Está obsoleto OrderedDict?
Mayormente; los dict regulares conservan el orden de inserción. Conserva OrderedDict para comportamientos LRU de move_to_end.
¿defaultdict o setdefault?
defaultdict es más limpio para la acumulación. setdefault está bien para claves faltantes ocasionales.
¿Puede Counter contar objetos?
Sí, si son hasheables. A menudo se cuentan cadenas o tuplas extraídas de registros.
¿Es deque seguro para hilos?
append/pop son seguros para hilos en CPython debido al GIL; aún así, coordina operaciones compuestas entre hilos.
¿Cómo usar ChainMap para la configuración de entorno?
ChainMap(os.environ, defaults): el entorno anula los valores predeterminados sin copiar.
¿most_common big-O?
Usa un heap para los N principales: eficiente cuando n << claves únicas.
¿namedtuple en collections?
Se ha avanzado hacia typing.NamedTuple y dataclasses; aún disponible como collections.namedtuple.
¿Counter elements()?
Expande los recuentos a elementos repetidos; útil para volver a alimentar el multiconjunto en algoritmos.
¿deque vs list como cola?
Nunca uses list.pop(0) en bucles activos (O(n)). Siempre usa deque.popleft().
¿Puedo serializar defaultdict?
Convierte primero a dict normal: dict(dd); la fábrica no se conserva en JSON de forma natural.
Relacionado
- Diccionarios - semántica del mapa subyacente
- heapq y Colas de Prioridad - ordenamiento
- Listas y Tuplas - cuándo deque supera a list
- Elegir la Estructura de Datos Correcta - guía de decisión
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.