函数默认参数在定义时创建并复用,可变对象(如列表)会因共享同一实例导致状态累积;安全做法是用None作默认值并在函数内新建对象。

因为函数的默认参数在定义时就创建并绑定到函数对象上,而不是每次调用时重新生成。
默认参数只在函数定义时求值一次
Python 中,函数定义(def 语句执行时)就会计算默认参数的值,并把该对象存储在函数的 __defaults__ 属性里。之后每次调用函数、没传对应参数时,就复用这个已存在的对象。
例如:
def append_to(item, lst=[]):
lst.append(item)
return lst
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] ← 不是 [2]
print(append_to(3)) # [1, 2, 3]
这里的 lst=[] 在 def 执行时创建了一个空列表对象,后续所有未传 lst 的调用都共用它。
可变对象被反复修改,状态持续累积
列表、字典、集合等可变对象支持原地修改(如 .append()、[key] = val),而默认参数引用的又是同一个对象,所以每次调用都在“往同一个容器里加东西”。
这和不可变对象(如 int、str、tuple)不同——它们无法原地修改,每次操作都会产生新对象,不会暴露共享状态问题。
安全写法:用 None 作占位符
惯用做法是把默认值设为 None,并在函数体内显式创建新对象:
- def append_to(item, lst=None):
- if lst is None:
- lst = []
- lst.append(item)
- return lst
这样每次调用都得到一个全新列表,互不影响。
可以验证默认参数对象是否被复用
通过检查函数的 __defaults__ 和对象 id:
print(id(append_to.__defaults__[0])) # 第一次调用前后 id 相同 append_to(1) print(id(append_to.__defaults__[0])) # 还是同一个 id
说明不是“记住了值”,而是根本就没换过对象。










