Buenas Prácticas de Colecciones
Reglas prácticas para elegir y usar los contenedores integrados de Python sin trampas de rendimiento ni deuda de legibilidad.
Cómo Usar Esta Lista
- Aplícala durante la revisión de código en módulos con mucha carga de datos.
- Revísala cuando el profiling muestre un comportamiento inesperado de O(n).
- Combínala con type hints (
dict[str, int]) para contratos más claros. - Úsala como lista de verificación de incorporación para código de canalización de datos.
A - Selección
- Elige
dictpara búsqueda por clave,setpara pertenencia,listpara secuencias ordenadas. Documenta las opciones no obvias. - Usa
dequepara colas FIFO/LIFO en lugar delist.pop(0). O(1) frente a O(n) al principio. - Usa
heapqpara planificación de prioridad;bisectpara inserciones ordenadas. Nosorted()en cada inserción. - Recurre a pandas 2.2+ o Polars 1.x a escala tabular, no a diccionarios anidados de listas. Operaciones de columna y uniones.
- Prefiere
Counterydefaultdictsobre el boilerplate manual de comprobación de existencia de clave. Menos ramas, intención más clara.
B - Corrección
- Nunca uses listas o diccionarios mutables como claves de
dicto elementos deset. Usatuple,frozensetodataclasscongelado. - Copia superficialmente estructuras anidadas con
copy.deepcopycuando se requiera independencia.dict.copy()comparte las listas internas. - Trata el orden de iteración de
setcomo no especificado. Usasorted(s)solo para visualización estable. - Valida la unicidad antes de invertir un
dict{v: k}. Los valores que colisionan se sobrescriben silenciosamente. - Usa
getotry/except KeyErrorintencionadamente.d[k]cuando la clave debe existir;getcuando es opcional.
C - Rendimiento y Memoria
- Construye
setuna vez para pertenencia repetida en bucles. Evitain listO(n) en rutas críticas. - Usa expresiones generadoras alimentando
sum/any/maxpara flujos grandes. Evita materializar listas de un millón de elementos. - Considera
array.arrayobytespara buffers numéricos/binarios compactos. No listas de enteros para protocolos de red. - Haz profiling antes de cambiar
listpor una estructura exótica.npequeño favorece la simplicidad. - Evita la repetición de
keys()a menos que mutes durante la iteración.list(d)al eliminar mientras iteras.
D - Legibilidad
- Usa comprensiones de
dict/setpara transformaciones con filtros opcionales. Más claro que bucles manuales. - Nombra los tipos en hints:
dict[str, list[Event]], nodictsolo. Estructuras auto-documentadas. - Usa
NamedTupleodataclassen lugar de indexación posicional detuplepara registros.row[3]oscurece el significado. - Prefiere la fusión
|para superposiciones de configuración inmutables (3.9+).base | overridesse lee de izquierda a derecha. - Deduplicación que preserva el orden:
list(dict.fromkeys(items)). Línea única idiomática.
E - Serialización y APIs
- Las APIs JSON solo usan
dict/list/str/int/float/bool/Noneen los límites. Convierteset/tuplealistpara JSON. - No confíes en el orden de
dictpara la igualdad semántica entre sistemas. Compara como mapeos, no como listas de claves. - Congela los diccionarios de configuración al inicio cuando pasen por capas.
MappingProxyTypeo un objeto de configuración tipado. - Documenta las semánticas de contenedores vacíos:
[]vsNone. Los llamadores no deben adivinar entre ausente o vacío. - Usa modelos Pydantic 2 en los límites HTTP; diccionarios simples dentro de la lógica de dominio crítica cuando sea apropiado.
Preguntas Frecuentes
¿Cuándo sigue estando justificado OrderedDict?
Patrones LRU move_to_end. El dict normal maneja el orden de inserción en caso contrario.
¿list o tuple en el retorno de la API?
tuple para pequeños paquetes fijos; list al devolver una colección homogénea de longitud variable.
¿Siempre debo usar slots?
__slots__ para millones de objetos pequeños de campos fijos. Prematuro para registros de aplicaciones típicas.
¿Counter vs defaultdict(int)?
Counter añade operadores de multiconjunto y most_common - prefiere para trabajo de frecuencia.
¿Cómo evitar sorpresas de serialización con defaultdict?
Convierte a dict(defaultdict) antes de JSON - la fábrica no se serializa.
¿Son las comprensiones siempre pythonicas?
Sí para transformaciones de map/filter. Cambia a bucle para efectos secundarios o ramificaciones complejas.
¿dict vs dataclass para registros?
dataclass/Pydantic para objetos de dominio con comportamiento; dict para pasar JSON o claves dinámicas.
¿Cuándo usar ChainMap?
Búsqueda de configuración en capas sin copiar - entorno sobre valores predeterminados. Aplana al persistir.
¿Vale la pena frozenset?
Cuando un conjunto de etiquetas debe ser una clave de dict o una entrada de caché - en caso contrario, set normal.
¿Mayor error con colecciones?
Búsqueda lineal en list dentro de un bucle - soluciona con índice de set/dict construido una vez.
Relacionado
- Elegir la Estructura de Datos Correcta - guía de decisión
- Conceptos Básicos de Estructuras de Datos - ejemplos introductorios
- Inmutabilidad y Hashabilidad - reglas de hash
- Módulo collections - tipos especializados
Versiones de la pila: 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+.