类实例不能直接作函数默认参数,因为默认参数在def时求值一次,导致所有调用共享同一实例,引发数据污染;应改用none并在函数体内惰性创建新实例。

为什么类实例不能直接当函数默认参数用
Python 函数的默认参数在 def 语句执行时求值一次,不是每次调用都新建。如果默认值是类实例(比如 MyClass()),那这个实例对象就会被所有不传参的调用共享——后续对它的任何修改(如修改属性、往列表里 append)都会持续累积,导致不同调用之间数据污染。
常见错误现象:def process(data, cache=CacheManager()),连续调用 process("a")、process("b") 后,cache 里同时存在 a 和 b 的记录,哪怕你本意是每次用干净的新缓存。
用 None 替代类实例作默认值
这是最直接、最可控的解法:把默认值设为 None,在函数体内按需创建新实例。
- 写法必须是
def func(x, cache=None):,不能写成cache=CacheManager() or None(or在定义时就执行了,失去惰性) - 初始化要放在函数体开头:
if cache is None: cache = CacheManager(),注意用is判断,不用== - 不要写成
cache = cache or CacheManager()——如果传入一个“假值”实例(比如cache内部__bool__返回False),会被误判并覆盖掉
类方法中传参也要防坑
类方法里用可变对象或类实例作默认参数,问题一样严重,而且更容易被忽略。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
-
def __init__(self, items=[], processor=DataProcessor())是高危写法,多个实例会共享同一个items列表和同一个processor实例 - 正确写法:
def __init__(self, items=None, processor=None),然后分别做if items is None: items = []和if processor is None: processor = DataProcessor() - 特别注意:如果
DataProcessor初始化开销大,可以考虑延迟创建(比如只在首次使用时初始化),但默认参数本身仍必须用None
验证是否真的隔离了实例
别靠肉眼猜,用 id() 或 is 直接验证:
def make_cache(cache=None):
if cache is None:
cache = CacheManager()
print(id(cache))
return cache
<p>make_cache() # 输出某个地址
make_cache() # 输出另一个地址(说明每次都是新实例)
</p>
如果两次输出相同地址,说明你没写对——大概率是默认值写成了 cache=CacheManager() 或用了 or 表达式。
真正容易被忽略的是:这个陷阱不报错,它只是悄悄让数据跨调用、跨实例“粘连”。上线后查日志发现用户 A 的操作影响了用户 B,往往已经晚了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










