用list实现栈需用append()和pop()(无参数)保证O(1)性能,禁用pop(0);推荐deque实现更安全高效;空栈pop会抛IndexError,须显式检查;LifoQueue仅适用于多线程场景。

用 list 实现栈:简单但要注意 pop() 性能陷阱
直接用 list 的 append() 和 pop() 就能模拟栈,因为默认 pop() 从末尾移除元素,符合 LIFO。但得记住:如果频繁在头部插入或删除(比如误用 pop(0)),时间复杂度会退化成 O(n)。
-
push对应list.append(x)—— O(1) 均摊 -
pop必须用list.pop()(不带参数)—— O(1) - 千万别写
list.pop(0),那是在模拟队列,不是栈,而且慢 - 检查是否为空得用
if not stack:,别写len(stack) == 0,虽等价但多一次函数调用
用 collections.deque 实现栈:更明确、更安全
deque 是双端队列,两端操作都是 O(1),语义上比 list 更贴近“栈”这种抽象数据类型。尤其适合你后续可能扩展成支持双向操作的场景(比如实现撤销/重做时加个 undo_stack 和 redo_stack)。
-
push用deque.append(x) -
pop用deque.pop()—— 和 list 一样,但底层无内存搬移风险 - 初始化写
from collections import deque; stack = deque(),别漏导入 - 如果项目里已大量用
list做栈且没性能问题,没必要强行换;但新代码建议优先deque
栈空时调用 pop() 报错:IndexError: pop from empty list
这是最常踩的坑——没做空检查就直接 pop()。Python 不提供类似 Java 的 empty() 方法,得自己守门。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 正确做法:先
if stack:再stack.pop(),或者用异常捕获(但仅限你确定“空”是异常路径) - 别依赖
try/except IndexError做常规控制流,这在 Python 里叫“EAFP 有道理,但太频繁就变慢” - 如果需要“弹出并返回默认值”,可以封装一层:
return stack.pop() if stack else None - 注意:
deque和list在空时抛的都是同一个IndexError,行为一致
为什么不用 queue.LifoQueue?它和栈有什么区别
LifoQueue 是线程安全的,内部用了锁,所有操作都带同步开销。如果你只是单线程做算法题、解析表达式或 DFS 遍历,完全没必要。
- 纯计算场景下,
LifoQueue.put()/LifoQueue.get()比deque.append()/deque.pop()慢 10 倍以上 - 它没有
peek()(查看栈顶不弹出)方法,也没len()直接获取大小(得用q.qsize(),但文档明确说“不保证实时准确”) - 只在你明确需要多线程协作 push/pop 时才考虑它,比如一个线程生成任务、多个线程消费,且顺序必须 LIFO
栈机制本身不难,难的是在具体上下文里选对结构、避开隐性成本。特别是当栈被嵌在递归下降解析器或状态机里时,一次 pop(0) 或误用 LifoQueue,可能让整体性能掉一个数量级,还不好定位。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










