Python默认参数陷阱:可变对象作为默认值
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哨兵模式。