collections.deque (pronounced "deck") es una cola de doble extremo optimizada para inserciones y eliminaciones O(1) por ambos lados. A diferencia de una lista, donde pop(0) es O(n), deque.popleft() es siempre O(1). El parámetro maxlen la convierte en un buffer circular que descarta automáticamente los elementos más antiguos.
Operaciones básicas: appendleft y popleft
from collections import deque d = deque([1, 2, 3]) # Por la derecha (igual que list) d.append(4) print(d) # deque([1, 2, 3, 4]) ultimo = d.pop() print(ultimo, d) # 4 deque([1, 2, 3]) # Por la izquierda (O(1), imposible en list) d.appendleft(0) print(d) # deque([0, 1, 2, 3]) primero = d.popleft() print(primero, d) # 0 deque([1, 2, 3])
deque como cola FIFO eficiente
from collections import deque
cola_tareas = deque()
# Añadir tareas al final
cola_tareas.append("tarea_1")
cola_tareas.append("tarea_2")
cola_tareas.append("tarea_3")
# Procesar en orden FIFO
while cola_tareas:
tarea = cola_tareas.popleft()
print(f"Procesando: {tarea}")
# Procesando: tarea_1
# Procesando: tarea_2
# Procesando: tarea_3
maxlen: buffer de tamaño fijo
Cuando la deque está llena y añades un elemento por la derecha, descarta automáticamente el elemento más antiguo (el de la izquierda). Al revés con appendleft():
from collections import deque
# Buffer de los últimos 5 valores de un sensor
buffer = deque(maxlen=5)
for valor in range(10):
buffer.append(valor)
print(list(buffer))
# [0]
# [0, 1]
# [0, 1, 2]
# [0, 1, 2, 3]
# [0, 1, 2, 3, 4]
# [1, 2, 3, 4, 5] ? 0 descartado
# [2, 3, 4, 5, 6]
# [3, 4, 5, 6, 7]
# [4, 5, 6, 7, 8]
# [5, 6, 7, 8, 9]
Historial de deshacer (undo) con maxlen
from collections import deque
class Editor:
def __init__(self, max_historial=10):
self.texto = ""
self.historial = deque(maxlen=max_historial)
def escribir(self, texto):
self.historial.append(self.texto)
self.texto += texto
def deshacer(self):
if self.historial:
self.texto = self.historial.pop()
else:
print("Nada que deshacer")
def __str__(self):
return f"'{self.texto}'"
e = Editor(max_historial=3)
e.escribir("Hola")
e.escribir(", ")
e.escribir("mundo")
print(e) # 'Hola, mundo'
e.deshacer()
print(e) # 'Hola, '
e.deshacer()
print(e) # 'Hola'
rotate(): desplazar elementos
from collections import deque
# Turnos rotativos
turnos = deque(["Ana", "Luis", "María", "Pedro"])
def siguiente_turno(d):
actual = d[0]
d.rotate(-1) # mueve el primero al final
return actual
for _ in range(6):
print(f"Turno: {siguiente_turno(turnos)}")
# Turno: Ana, Luis, María, Pedro, Ana, Luis...
deque vs list: cuándo usar cada una
# list: acceso por índice O(1), append/pop al final O(1) # pop(0) / insert(0, x) son O(n) # deque: appendleft/popleft O(1), append/pop O(1) # acceso por índice O(n) para el centro # Regla: si solo operas en los extremos ? deque # si necesitas acceso aleatorio ? list
deque es la estructura correcta siempre que necesites una cola FIFO, un buffer de tamaño fijo o una pila bidireccional. Para acceso aleatorio frecuente a elementos intermedios, la lista sigue siendo mejor opción.
