krahets/hello-algo · error · IndexError
двусторонняя очередь пуста
Error message
двусторонняя очередь пуста
What it means
Raised by LinkedListDeque.pop(is_front) in chapter_stack_and_queue/linkedlist_deque.py:66 — IndexError("двусторонняя очередь пуста"). This is the internal removal routine called by pop_first()/pop_last(); it refuses to unlink from an empty deque because self._front/self._rear would be None. Note the public API is pop_first()/pop_last(); pop(is_front) is the shared private helper.
Source
Thrown at ru/codes/python/chapter_stack_and_queue/linkedlist_deque.py:66
else:
# Добавить node в хвост списка
self._rear.next = node
node.prev = self._rear
self._rear = node # Обновить хвостовой узел
self._size += 1 # Обновить длину очереди
def push_first(self, num: int):
"""Добавление в голову очереди"""
self.push(num, True)
def push_last(self, num: int):
"""Добавление в хвост очереди"""
self.push(num, False)
def pop(self, is_front: bool) -> int:
"""Операция извлечения из очереди"""
if self.is_empty():
raise IndexError("двусторонняя очередь пуста")
# Операция извлечения из головы очереди
if is_front:
val: int = self._front.val # Временно сохранить значение головного узла
# Удалить головной узел
fnext: ListNode | None = self._front.next
if fnext is not None:
fnext.prev = None
self._front.next = None
self._front = fnext # Обновить головной узел
# Операция извлечения из хвоста очереди
else:
val: int = self._rear.val # Временно сохранить значение хвостового узла
# Удалить хвостовой узел
rprev: ListNode | None = self._rear.prev
if rprev is not None:
rprev.next = None
self._rear.prev = None
self._rear = rprev # Обновить хвостовой узелView on GitHub (pinned to 69932aed18)
Solutions
- Guard the public call: if not dq.is_empty(): dq.pop_first().
- Use is_empty() as the termination condition for two-ended draining.
- Wrap pop_first/pop_last in try/except IndexError for best-effort removal.
- Track logical element count so pops never exceed pushes.
Example fix
// before x = dq.pop_first() // after x = dq.pop_first() if not dq.is_empty() else None
Defensive patterns
Strategy: validation
Validate before calling
def safe_pop_first(dq):
return dq.pop_first() if not dq.is_empty() else None Type guard
def deque_non_empty(dq) -> bool:
return not dq.is_empty() Try / catch
try:
x = dq.pop_first() # delegates to private pop(is_front=True)
except IndexError:
x = None Prevention
- Call the public pop_first/pop_last, not the private pop(is_front)
- Use is_empty() as the two-ended drain condition
- Track logical count so pops never exceed pushes
When it happens
Trigger: Calling pop_first() or pop_last() on an empty deque (both delegate here). More pops than pushes from either end. Asymmetric use (push only on one end, pop on the other) until drained.
Common situations: Palindrome/two-pointer deque algorithms that overshoot the middle. Consumer outrunning producer on a shared deque. Cleanup that pops remaining elements twice.
Related errors
- двусторонняя очередь пуста
- очередь пуста
- Double-ended queue is empty
- Double-ended queue is empty
- куча пуста
AI-assisted analysis of krahets/hello-algo@69932aed18 (2026-08-13).
Data as JSON: /api/errors/27b9cfff600a4e5f.
Report an issue: GitHub.