Python函数默认参数为何在调用间保留值?新手技术问询
为什么Python函数的可变默认参数会保留之前的状态?
这绝对是Python新手最容易踩的坑之一!我来给你拆解清楚到底发生了什么:
核心原因:默认参数的初始化时机
你以为每次调用func()的时候,b=set()都会重新创建一个新的空集合?其实不是!Python的函数默认参数是在函数被定义的那一刻初始化的,而不是每次调用函数的时候。
也就是说,当你写下def func(a,b=set()):这行代码时,这个空集合set()就已经被创建出来了,并且会一直复用这个同一个对象——只要你调用函数时没有手动传入b参数,就会用这个已经存在的集合。
结合你的代码一步步看
第一次调用
func([1,1,2,2,3,4])- 此时
b用的是定义函数时创建的那个空集合set()。 - 循环过程中,你把每个
i都添加到了b里,最后b变成了{1,2,3,4},同时返回的res是第一次出现的元素[1,2,3,4]。
- 此时
第二次调用
func([1,1,2,2,3,4])- 你依然没有传入
b参数,所以Python还是用之前那个已经被修改成{1,2,3,4}的集合。 - 循环里每个
i都已经在b里了,所以res里没有添加任何元素,最终返回[]。
- 你依然没有传入
你添加print(b)后看到的输出也完全符合这个逻辑:第一次调用前b是空集合,调用后被修改;第二次调用前b已经是{1,2,3,4}了,自然不会有新元素加入res。
怎么解决这个问题?
如果你希望每次调用函数时都使用一个全新的空集合,应该把默认参数设为None,然后在函数内部初始化b:
def func(a, b=None): # 如果没有传入b,就创建一个新的空集合 if b is None: b = set() res = list() for i in a: if i not in b: res.append(i) b |= {i} return res
这样每次调用时,只要没传b,都会生成一个新的空集合,就不会出现之前的“残留状态”问题了。
额外提醒
这个坑不止出现在set上,所有可变类型(比如list、dict)作为默认参数时都会有这个问题——因为它们是可变对象,修改会直接改变原对象的状态,影响后续的函数调用。
内容的提问来源于stack exchange,提问作者Mar Ok
相关产品推荐
相关产品推荐

