Python中函数默认参数在定义时只求值一次,若为可变对象(如[]),多次调用会共享同一实例,导致意外修改;正确做法是用None作默认值并在函数内初始化。

为什么 def __init__(self, items=[]) 是危险的
Python 中函数(包括 __init__)的默认参数在定义时只求值一次,而不是每次调用时重新创建。当默认值是可变对象(如 []、{}、set())时,所有未显式传参的实例会共享同一个对象。结果就是:一个实例修改了 items,其他实例也跟着变——这不是 bug,是语言机制,但极易引发隐蔽逻辑错误。
常见现象:obj1.add_item('a'); print(obj2.items) 却输出 ['a'],而你根本没动 obj2。
- 该问题不限于
__init__,所有带默认可变参数的函数都适用 - 静态分析工具(如
pylint)通常会报W0102警告 - 类型检查器(如
mypy)不会捕获此问题,它只看类型签名,不关心可变性
正确写法:用 None 作占位符并手动初始化
标准解法是把默认值设为不可变的 None,然后在方法体内判断并分配新对象。这样每次调用都获得独立副本。
class Box:
def __init__(self, items=None):
self.items = items if items is not None else []
注意必须用 is not None 判断,不能用 if not items——因为 []、{}、0、False 都是 falsy,会导致传入空列表也被覆盖。
立即学习“Python免费学习笔记(深入)”;
创建 Flask + Vue.js 全栈项目,采用单端口架构、uv 依赖管理、结构化日志和生产级前端设计。当用户要求以下操作时触发:创建新的 Flask+Vue 项目、搭建 Web 应用、构建全栈 Python+Vue 应用、初始化 Flask Web 项目、设置单端口 Flask 前后端项目。触发词:新建项目、创建项目、搭建项目、Flask项目、Vue项目。
- 如果想支持传入
None表示“真·空”,那就需要额外约定或文档说明 - 对字典、集合同理:
data=None→self.data = data if data is not None else {} - 若需深拷贝(比如默认值本身来自某个全局模板),则用
copy.deepcopy()替代直接赋值
进阶场景:需要默认值是“每次新建”的可变对象
有时你希望默认行为是生成一个带预设内容的新对象(例如默认含 ['default'] 的列表),而非空容器。这时仍不能写死 items=['default'],而应封装成工厂函数或使用延迟求值。
class TaskQueue:
def __init__(self, queue=None):
self.queue = queue if queue is not None else ['pending']
上面看似写了字面量,但它只在 queue is None 分支内执行,每次调用都新建列表,安全。
- 避免在默认参数位置直接调用构造函数(如
def __init__(self, log=Logger())),这仍是定义时求值 - 若工厂逻辑复杂,可提取为私有方法:
self.log = log if log is not None else self._make_default_logger() - 不要依赖
lambda或闭包来“绕过”——它们也不能改变默认参数只初始化一次的本质
类型提示怎么写才准确
用 Optional 表达“可能为 None”,再配合类型注释明确实际字段类型。否则类型检查器会认为字段可能是 None,后续访问要加非空断言,徒增麻烦。
from typing import Optional, List
class Box:
def __init__(self, items: Optional[List[str]] = None) -> None:
self.items: List[str] = items if items is not None else []
关键点在于:参数类型声明为 Optional[List[str]],但实例属性 self.items 的类型是确定的 List[str],这样后续代码无需反复处理 None。
- 别写
items: List[str] = []—— 类型提示和运行时行为矛盾,mypy 可能误报 - Python 3.10+ 可用
items: list[str] | None = None,语义更清晰 - 如果类被继承,子类重写
__init__时也要沿用相同模式,否则破坏封装性
= [] 或 = {},就得本能地查文档或源码确认它是否安全——哪怕它看起来“只是个配置参数”。

















