CodeWalk

Python默认参数陷阱:可变对象作为默认值

作者:孤独的心 · 2026-05-30 12:55

Python函数定义时使用可变对象(如[]{})作为默认参数会有什么问题?请解释其根本原因(函数定义时还是调用时求值),并给出正确的解决方案。

回答

孤独的心

陷阱示例

def add_item(item, lst=[]):  # 陷阱!
    lst.append(item)
    return lst

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2]  <- 不是[2]!
print(add_item(3))  # [1, 2, 3]

根本原因

默认参数在函数定义时求值(编译期),而非调用时。

  • 函数定义时,Python创建默认值对象(空列表[])并绑定到函数对象上
  • 每次调用修改该对象,都会影响后续调用
  • 可通过add_item.__defaults__查看默认参数值
print(add_item.__defaults__)  # ([1, 2, 3],)

正确解决方案

使用None哨兵 + 函数体内创建新对象:

def add_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

print(add_item(1))  # [1]
print(add_item(2))  # [2]  <- 正确!

惰性求值陷阱

类似问题也会出现在惰性求值场景:

def create_multipliers():
    return [lambda x: i * x for i in range(4)]

for m in create_multipliers():
    print(m(2))
# 输出6 6 6 6,不是0 2 4 6
# 因为闭包捕获的是变量i的引用,循环结束后i=3

**面试重点:**解释「定义时求值」是Python设计决策(性能优化),需自觉用None哨兵模式。