{"record":{"id":"acc541683d0a6bc6","repo":"krahets/hello-algo","slug":"error-acc541","errorCode":null,"errorMessage":"двусторонняя очередь пуста","messagePattern":"двусторонняя очередь пуста","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"ru/codes/python/chapter_stack_and_queue/array_deque.py","lineNumber":76,"sourceCode":"\n    def pop_first(self) -> int:\n        \"\"\"Извлечение из головы очереди\"\"\"\n        num = self.peek_first()\n        # Указатель головы сдвигается на одну позицию назад\n        self._front = self.index(self._front + 1)\n        self._size -= 1\n        return num\n\n    def pop_last(self) -> int:\n        \"\"\"Извлечение из хвоста очереди\"\"\"\n        num = self.peek_last()\n        self._size -= 1\n        return num\n\n    def peek_first(self) -> int:\n        \"\"\"Доступ к элементу в начале очереди\"\"\"\n        if self.is_empty():\n            raise IndexError(\"двусторонняя очередь пуста\")\n        return self._nums[self._front]\n\n    def peek_last(self) -> int:\n        \"\"\"Доступ к элементу в конце очереди\"\"\"\n        if self.is_empty():\n            raise IndexError(\"двусторонняя очередь пуста\")\n        # Вычислить индекс хвостового элемента\n        last = self.index(self._front + self._size - 1)\n        return self._nums[last]\n\n    def to_array(self) -> list[int]:\n        \"\"\"Вернуть массив для вывода\"\"\"\n        # Преобразовывать только элементы списка в пределах фактической длины\n        res = []\n        for i in range(self._size):\n            res.append(self._nums[self.index(self._front + i)])\n        return res\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/ru/codes/python/chapter_stack_and_queue/array_deque.py#L58-L94","documentation":"Raised by ArrayDeque.peek_first() in chapter_stack_and_queue/array_deque.py:76 — IndexError(\"двусторонняя очередь пуста\" = \"deque is empty\"). peek_first reads self._nums[self._front]; on an empty deque _front may point at a stale slot, so the guard is required to avoid returning garbage. pop_first() internally calls peek_first(), so it propagates the same error when empty.","triggerScenarios":"Calling peek_first() (or pop_first(), which delegates to it) on an empty deque. Draining the deque with repeated pop_first without checking is_empty().","commonSituations":"Unbalanced push/pop counts. Processing a stream that yields no elements before the first pop. Reusing a deque across batches without resetting size checks.","solutions":["Guard: if not dq.is_empty(): dq.peek_first().","Make is_empty() the loop condition for draining.","Use pop_first's delegation: catch IndexError at the call site if best-effort.","Track expected element count upstream so pop is never called on empty."],"exampleFix":"// before\nx = dq.peek_first()\n// after\nx = dq.peek_first() if not dq.is_empty() else None","handlingStrategy":"validation","validationCode":"def safe_peek_first(dq):\n    return dq.peek_first() if not dq.is_empty() else None","typeGuard":"def deque_non_empty(dq) -> bool:\n    return not dq.is_empty()","tryCatchPattern":"try:\n    x = dq.peek_first()\nexcept IndexError:\n    x = None","preventionTips":["Balance push_first/push_last with pop counts","Use is_empty() as drain-loop condition","pop_first delegates to peek_first — guard once at the call site"],"tags":["indexerror","deque","ring-buffer","precondition","empty-state","python"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}