🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

¡No más KeyError! Sube de nivel tu código con el módulo collections de Python

Para ejecutar Python desde el símbolo del sistema o PowerShell en tu PC, necesitas descargar e instalar Python.
Si aún no lo has hecho, consulta el artículo Instalación de Python y configuración del entorno de desarrollo para instalar Python.

¡Hola! Soy yo, la persona que, con la ayuda de la IA, ha creado dos sitios web en solo unos meses de experiencia en programación.

Hoy voy a explicar de una manera sencilla el súper útil módulo "collections" de Python, una de esas cosas que desearía haber conocido antes en mi viaje de aprendizaje, ¡y hasta compartiré algunos de mis propios errores!

Será especialmente útil si alguna vez has luchado con el error `KeyError` en los diccionarios (`dict`) o has sentido que tus operaciones con listas (`list`) son un poco lentas. ¡Para cuando termines de leer este artículo, tu código de Python será sin duda mucho más inteligente! He evitado la jerga técnica y he preparado un montón de código listo para copiar y pegar, ¡así que vamos a experimentar juntos cómo hacer que las cosas "funcionen"!


Para empezar, ¿qué es el módulo collections?

La palabra "módulo" puede sonar complicada, pero piénsalo como una "práctica caja de herramientas que viene de serie con Python". No necesitas instalar nada extra; solo escribe una línea con `import` y estarás listo para empezar.

Dentro de esta caja de herramientas encontrarás utilidades especiales que hacen que las estructuras de datos básicas de Python, como los `dict` (diccionarios) y `list` (listas), sean aún más potentes y fáciles de usar. En este artículo, me centraré en dos herramientas que me parecieron particularmente impresionantes: `defaultdict` y `deque`.


`defaultdict`: La caja mágica que evita los errores por descuido en los diccionarios

Qué difícil es sin `defaultdict`... (Mi historia de fracaso)

¿Alguna vez has estado usando un diccionario (`dict`) y te has encontrado con un error como este?

# Intentando acceder a una clave que no existe en un diccionario normal
word_counts = {}
# La clave 'apple' aún no existe
word_counts['apple'] += 1 # ¡Error aquí!

# Resultado de la ejecución
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# KeyError: 'apple'

Este es un `KeyError`, que es la forma que tiene Python de decirte: "¡Oye, esa clave no existe en el diccionario!". Cuando estaba construyendo mis sitios web, pasé horas atascado en este error mientras intentaba procesar los datos de entrada del usuario.

Puedes prevenir este error comprobando si una clave existe con una sentencia `if` o usando el método `get()`, pero eso hace el código un poco más largo, ¿verdad?


¡Y llega el salvador, `defaultdict`!

`defaultdict` es lo que resuelve este problema de `KeyError` de un plumazo. Es un diccionario mágico que "crea automáticamente un 'valor por defecto' cuando accedes a una clave que no existe".

Ver para creer. Echemos un vistazo al código.

from collections import defaultdict

# Creamos un defaultdict donde el valor por defecto es 0 al especificar int
word_counts = defaultdict(int)

# La clave 'apple' aún no existe... ¡pero no pasa nada!
print(f"Antes de acceder: {word_counts}") # Está vacío antes de acceder
word_counts['apple'] += 1 # ¡Sin error! Crea automáticamente word_counts['apple'] = 0 y luego lo incrementa en 1
print(f"Después de acceder: {word_counts}")
print(f"Número de manzanas: {word_counts['apple']}")
print(f"Número de naranjas: {word_counts['orange']}") # 'orange' tampoco existe, pero al acceder devuelve el valor por defecto 0

¡Genial!, ¿verdad? Al escribir `defaultdict(int)`, le estás diciendo: "Si una clave no existe, por favor, establece automáticamente su valor inicial en `int()`, que es `0`". Esto te permite empezar a hacer cálculos de inmediato sin preocuparte por un `KeyError`.
Este comportamiento se describe en la documentación oficial de Python como "devuelve un valor por defecto para una clave inexistente", lo que la convierte en una característica muy fiable.


[Listo para copiar y pegar] Ejemplo de aplicación: Contar la frecuencia de palabras en un texto

`defaultdict` es especialmente útil cuando necesitas contar cosas. Por ejemplo, puedes contar fácilmente cuántas veces aparece cada palabra en un texto, así:

from collections import defaultdict

sentence = "apple banana apple orange banana apple"
words = sentence.split() # Divide la frase en una lista de palabras

# Un defaultdict donde el valor por defecto es 0 al especificar int
word_counts = defaultdict(int)

for word in words:
  word_counts[word] += 1

# Muestra los resultados
for word, count in word_counts.items():
  print(f"'{word}': {count} veces")

# También puedes convertirlo en un dict normal para comprobar el contenido
print(f"\nContenido final del diccionario: {dict(word_counts)}")

Intenta copiar, pegar y ejecutar este código. Verás que cuenta las palabras con precisión sin una sola sentencia `if`. ¡Ese es el poder de `defaultdict`!


`deque`: La cola de alta velocidad que soluciona la "lentitud" de las listas

Añadir/eliminar del principio de una lista es en realidad ineficiente

Lo siguiente es `deque` (se pronuncia "dek"). Es muy similar a una lista (`list`), pero tiene una característica especial: es increíblemente rápido para añadir y eliminar elementos del principio.

La verdad es que, aunque la `list` de Python es buena para añadir al final (lado derecho) con `append`, no es muy buena para añadir al principio (lado izquierdo) con `insert(0, ...)` o eliminar de él con `pop(0)`.

Esto se debe a que cuando añades o eliminas un elemento al principio de una lista, cada elemento posterior tiene que ser desplazado uno por uno. Es como colarse en una larga fila de personas o que la persona del frente se vaya: todos los que están detrás tienen que moverse. Cuantos más elementos haya, más trabajo se convierte este "desplazamiento" y más lento se vuelve el proceso.


¡Deja las operaciones en ambos extremos a `deque`!

`deque` fue creado para resolver este mismo problema. Utiliza una ingeniosa estructura interna (llamada lista doblemente enlazada) que hace que añadir o eliminar elementos de cualquiera de los extremos sea una operación instantánea, sin importar cuántos elementos haya.

Veámoslo también en código. Las operaciones que harías con una lista se pueden hacer con un `deque` usando nombres de métodos más intuitivos, y mucho más rápido.

from collections import deque

# Crear un deque
tasks = deque(['task2', 'task3'])
print(f"Estado inicial: {tasks}")

# Añadir al final (igual que el append de list)
tasks.append('task4')
print(f"Añadido al final: {tasks}")

# Añadir al principio (¡más rápido que insert(0,...) de list!)
tasks.appendleft('task1')
print(f"Añadido al principio: {tasks}")

# Eliminar del principio (¡más rápido que pop(0) de list!)
first_task = tasks.popleft()
print(f"Tarea extraída del principio: {first_task}")
print(f"Estado actual: {tasks}")

[Listo para copiar y pegar] Ejemplo de aplicación: Lista de artículos vistos recientemente (con un límite máximo)

`deque` es extremadamente útil para gestionar tareas o historiales. Con su función `maxlen`, puedes crear fácilmente una lista que "siempre mantiene solo los últimos N elementos".

Imagina una función de "Artículos vistos recientemente" en un sitio de comercio electrónico.

from collections import deque
import time

# Crear un deque que guarde un máximo de 5 elementos en el historial
history = deque(maxlen=5)

products = ['Camiseta', 'Zapatillas', 'Gorra', 'Sudadera', 'Chaqueta', 'Pantalones cortos']

for product in products:
  print(f"Viendo '{product}'.")
  history.append(product)
  print(f"Historial de visualización actual: {list(history)}") # Convertir a list() facilita la visualización
  time.sleep(1) # esperar 1 segundo

print("\n--- Historial de visualización final (Últimos 5 artículos) ---")
for item in history:
  print(item)

Cuando ejecutas este código, verás que a medida que se añade un nuevo artículo, el más antiguo es automáticamente expulsado y desaparece. Si tuvieras que implementar esto tú mismo con una `list`, necesitarías una comprobación como `if len(list) > 5:`, pero con `deque(maxlen=N)`, eso no es necesario. ¡Inteligente!, ¿no?


[¡Pruébalo!] Un contador de palabras que funciona en tu navegador

He preparado un ejemplo para que puedas experimentar la comodidad de `defaultdict` ahora mismo en tu navegador. Copia todo el código HTML de abajo, pégalo en un editor de texto y guárdalo con un nombre como "test.html". Luego, abre ese archivo en tu navegador.

Este no es código de Python, pero reproduce el concepto de `defaultdict` de "inicializar automáticamente un valor aunque la clave no exista" usando JavaScript. ¡Intenta introducir algo de texto en el área de texto y pulsa el botón!

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Demo de Contador de Palabras</title>
  <style>
    body { font-family: sans-serif; background-color: #202124; color: #e8eaed; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
    .container { width: 90%; max-width: 600px; padding: 2rem; border: 1px solid #5f6368; border-radius: 8px; }
    h1 { color: #669df6; }
    textarea { width: 100%; height: 150px; background-color: #3c4043; color: #e8eaed; border: 1px solid #5f6368; border-radius: 4px; padding: 10px; font-size: 1rem; margin-bottom: 1rem; }
    button { background-color: #8ab4f8; color: #202124; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-weight: bold; }
    button:hover { opacity: 0.9; }
    #result { margin-top: 1.5rem; background-color: #282a2d; padding: 1rem; border-radius: 4px; }
    pre { white-space: pre-wrap; word-wrap: break-word; }
  </style>
</head>
<body>
  <div class="container">
    <h1>Contador de Palabras</h1>
    <p>Introduce texto en el cuadro de abajo y pulsa el botón.</p>
    <textarea id="text-input" placeholder="Introduce texto aquí... (ej: manzana plátano manzana naranja)"></textarea>
    <button onclick="countWords()">Contar Palabras</button>
    <div id="result">
      <pre>Los resultados se mostrarán aquí.</pre>
    </div>
  </div>

  <script>
    function countWords() {
      const text = document.getElementById('text-input').value;
      const resultEl = document.getElementById('result');

      if (!text.trim()) {
        resultEl.innerHTML = '<pre>No se ha introducido texto.</pre>';
        return;
      }

      // Dividir en palabras por espacios o saltos de línea y eliminar elementos vacíos
      const words = text.toLowerCase().match(/\b(\w+)\b/g) || [];

      // Emular el comportamiento de defaultdict(int)
      const counts = {}; 
      for (const word of words) {
        // Si la clave no existe, la establece en 0 y luego la incrementa
        counts[word] = (counts[word] || 0) + 1;
      }

      // Formatear y mostrar el resultado
      let resultText = '[Resultado del conteo]\n';
      for (const [word, count] of Object.entries(counts)) {
        resultText += `"${word}": ${count} veces\n`;
      }
      
      resultEl.innerHTML = `<pre>${resultText}</pre>`;
    }
  </script>
</body>
</html>

Puntos a tener en cuenta al usar `collections`

Finalmente, permíteme mencionar algunos pequeños puntos a tener en cuenta al usar estas prácticas herramientas.


Resumen: Programa de forma más inteligente y lleva tu programación al siguiente nivel

En este artículo, hemos presentado `defaultdict` y `deque` del módulo estándar "collections" de Python, dos herramientas que es especialmente útil conocer desde las primeras etapas del aprendizaje.

Desde que aprendí sobre estas herramientas, mi propio código se ha vuelto más simple y el tiempo que paso depurando errores ha disminuido drásticamente. Te animo a que empieces copiando y pegando el código de este artículo para que experimentes su comodidad por ti mismo. Aunque dominar las `list` y `dict` básicas es importante, ¡usar herramientas prácticas como las de `collections` en los lugares adecuados te ayudará a escribir un código más eficiente y legible!

Próximos pasos

Ahora que has experimentado la comodidad del módulo `collections`, ¿por qué no intentas construir una aplicación basada en texto? ¡Disfrutemos de la diversión de crear algo que funcione usando estructuras de datos básicas!

Construyamos una aplicación de lista de tareas en Python (basada en texto)