Python deque 实战:双端队列、栈与定长缓存

2026-08-18 26 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:5 分钟

如果一个列表需要频繁从头部插入或删除,list 往往不是最合适的工具。Python 标准库中的 collections.deque 专门面向双端操作:可以快速地从左端或右端追加、弹出元素,也能用同一套接口构建队列、栈和定长缓存。

理解 deque 的关键,不是记住几个方法名,而是判断数据应该从哪一端进入、从哪一端离开,以及是否需要让容器自动淘汰旧数据。

两端操作是核心

deque 的名字来自 double-ended queue,表示“双端队列”。它支持以下常用操作:

  • append(value):从右端追加元素
  • appendleft(value):从左端追加元素
  • pop():从右端移除并返回元素
  • popleft():从左端移除并返回元素

这些操作适合处理需要先进先出、后进先出,或者需要同时操作两端的场景。与其把列表的头部当作队列出口,不如直接使用 popleft() 表达意图。

用同一个 deque 构建队列和栈

队列通常遵循先进先出(FIFO):元素从右端进入,从左端离开。栈则遵循后进先出(LIFO):元素从右端进入,也从右端离开。

下面的例子可以直接运行,分别演示两种用法:

from collections import deque

# 队列:先进先出
queue = deque(["task-1", "task-2"])
queue.append("task-3")
print(queue.popleft())  # task-1
print(queue)           # deque(['task-2', 'task-3'])

# 栈:后进先出
stack = deque()
stack.append("page-home")
stack.append("page-products")
stack.append("page-detail")
print(stack.pop())      # page-detail
print(stack)            # deque(['page-home', 'page-products'])

这里的选择很明确:队列使用 append()popleft(),栈使用 append()pop()。如果业务代码中出现大量 list.pop(0),可以考虑改成 deque.popleft(),让数据结构和访问模式保持一致。

maxlen:自动维护最近 N 个元素

创建 deque 时可以指定 maxlen,让它只保留固定数量的元素。当新元素加入已满的双端队列时,另一端最旧的元素会自动被移除。

from collections import deque

recent_events = deque(maxlen=3)

for event in ["login", "view", "search", "logout"]:
    recent_events.append(event)
    print(list(recent_events))

# 输出:
# ['login']
# ['login', 'view']
# ['login', 'view', 'search']
# ['view', 'search', 'logout']

这个行为适合实现最近操作记录、滚动窗口和有限大小的事件缓存。需要注意的是,自动淘汰发生在插入时,代码不会收到额外的回调或异常;如果旧数据不能被静默丢弃,就不应只依赖 maxlen

从左端插入时,淘汰方向也会相应改变:

from collections import deque

numbers = deque([2, 3, 4], maxlen=3)
numbers.appendleft(1)

print(numbers)  # deque([1, 2, 3])

做题时的判断清单

遇到 deque 相关问题,可以按下面的顺序检查:

  1. 数据是否需要从两端频繁添加或删除?如果是,考虑 deque
  2. 是否是先进先出?使用 append() 配合 popleft()
  3. 是否是后进先出?使用 append() 配合 pop()
  4. 是否只保留最近的固定数量?创建时设置 maxlen
  5. 是否需要随机访问中间元素?如果访问重点是索引和中间位置,列表可能更直接;deque 的优势集中在两端操作。

掌握这些组合后,deque 的大多数基础题目都可以转化为一个简单问题:元素从哪一端进,从哪一端出。先确定这个方向,再选择对应的方法,代码通常会更短,也更容易验证。


相关推荐