函数默认参数为可变对象(如列表、字典)时,该对象在函数定义时创建并复用,导致多次调用间状态共享;正确做法是用none作默认值并在函数内初始化。

def func(items=[]): 这行代码实际在干啥
它不是“每次调用都新建一个空列表”,而是在 def 语句执行时,立刻创建一个空列表对象,并把它塞进函数对象的 __defaults__ 元组里。这个列表内存地址从此固定,所有没传 items 参数的调用,拿到的都是同一个对象。
为什么 if not items: lst = [] 会失效
因为 if not items: 在 items 是空列表时也成立,导致你每次都在重建——但问题不在这里,真正危险的是:你本意是“没传参时给个新列表”,却误用了可变默认值,让 items 本身就可能携带上一次调用留下的脏数据。
- 错误写法:
def f(lst=[]): ...→lst已经是共享对象 - 安全写法:
def f(lst=None): if lst is None: lst = [] - 永远别用
if not lst:判断,空列表、空字典、空字符串都为False,会掩盖真实意图
哪些地方最容易默默中招
这类 bug 往往不报错,只在特定调用序列下暴露,排查成本极高。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- Django/Flask 视图函数里写
def view(request, errors=[])→ 不同用户请求共用同一errors列表 - 递归辅助函数如
def dfs(node, path=[])→ 多条搜索路径的path互相污染 - 带
@lru_cache的函数若含cache={}默认参数 → 缓存键计算异常,甚至缓存击穿 - 类方法里写
def method(self, opts={})→ 所有实例调用共享同一字典
检查和修复现有代码的实操建议
别靠肉眼扫,直接用工具+运行时验证。
- 用
pylint检查,它会报dangerous-default-value警告 - 全局搜正则:
=\s*(\[|\{|\s*set\(\)),重点看函数参数定义行 - 运行时验证:
id(func()) == id(func())返回True就说明踩坑了 - 嵌套结构也要小心,比如
def f(d={"k": []})—— 外层 dict 安全,但里面的[]仍是共享的
最麻烦的不是语法错,而是它看起来总对,直到并发、递归或多次调用才突然崩掉。修复成本远低于定位成本。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










