{"record":{"id":"c645756955cb0781","repo":"krahets/hello-algo","slug":"error-c64575","errorCode":null,"errorMessage":"双向队列为空","messagePattern":"双向队列为空","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"codes/python/chapter_stack_and_queue/linkedlist_deque.py","lineNumber":66,"sourceCode":"        else:\n            # 将 node 添加至链表尾部\n            self._rear.next = node\n            node.prev = self._rear\n            self._rear = node  # 更新尾节点\n        self._size += 1  # 更新队列长度\n\n    def push_first(self, num: int):\n        \"\"\"队首入队\"\"\"\n        self.push(num, True)\n\n    def push_last(self, num: int):\n        \"\"\"队尾入队\"\"\"\n        self.push(num, False)\n\n    def pop(self, is_front: bool) -> int:\n        \"\"\"出队操作\"\"\"\n        if self.is_empty():\n            raise IndexError(\"双向队列为空\")\n        # 队首出队操作\n        if is_front:\n            val: int = self._front.val  # 暂存头节点值\n            # 删除头节点\n            fnext: ListNode | None = self._front.next\n            if fnext is not None:\n                fnext.prev = None\n                self._front.next = None\n            self._front = fnext  # 更新头节点\n        # 队尾出队操作\n        else:\n            val: int = self._rear.val  # 暂存尾节点值\n            # 删除尾节点\n            rprev: ListNode | None = self._rear.prev\n            if rprev is not None:\n                rprev.next = None\n                self._rear.prev = None\n            self._rear = rprev  # 更新尾节点","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/codes/python/chapter_stack_and_queue/linkedlist_deque.py#L48-L84","documentation":"IndexError '双向队列为空' (deque is empty) raised by LinkedListDeque.pop (the shared front/back removal routine). Removing from an empty doubly-linked list would dereference a None head/rear, so the guard blocks it. pop_first and pop_last both delegate here.","triggerScenarios":"Calling deque.pop_first() or deque.pop_last() when the deque holds no nodes.","commonSituations":"Work-stealing or BFS front/back draining where one end is exhausted before the other; symmetric processing that assumes both ends stay non-empty; calling pop_last on a freshly constructed deque.","solutions":["Guard with is_empty() before pop_first or pop_last.","In two-ended loops, check emptiness between every pop, not once per iteration.","If a pop is optional, route through a helper that returns a default."],"exampleFix":"// before\nval = dq.pop_last()  # raises when drained\n// after\nval = dq.pop_last() if not dq.is_empty() else None","handlingStrategy":"validation","validationCode":"def safe_pop(dq, front=True):\n    return dq.pop(front) if not dq.is_empty() else None","typeGuard":"def deque_non_empty(dq) -> bool:\n    return not dq.is_empty()","tryCatchPattern":"try:\n    val = dq.pop_first()\nexcept IndexError:\n    val = None","preventionTips":["Check is_empty() before every pop_first or pop_last.","In two-ended loops, re-check emptiness between pops.","Route optional pops through a default-return helper."],"tags":["deque","linked-list","index-error","empty-structure","pop"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}