为何用函数定义Python函数默认参数会引发信息泄露?
Python默认参数的陷阱:可变对象与不可变对象的差异
我尝试用另一个函数生成的标准字典作为函数默认参数,但第二次调用函数时,前一次运行的修改会泄露到第二次调用中。
问题复现代码
standard_list = ['a','b','c','d'] my_list = ['b','d'] my_second_list = ['a','b'] def init_dict(): my_dict = {} for key in standard_list: my_dict[key]=0 return my_dict def create_shopping_dict(shopping_list, standard_dict=init_dict()): for key in shopping_list: standard_dict[key]=1 return standard_dict my_shopping_list = create_shopping_dict(my_list) my_second_shopping_list = create_shopping_dict(my_second_list) print(my_second_shopping_list)
预期输出
{'a': 1, 'b': 1, 'c': 0, 'd': 0}
实际输出
{'a': 1, 'b': 1, 'c': 0, 'd': 1}
可行的修改方案
将standard_dict的初始化移至函数内部即可解决问题,但我不理解原因:
def create_shopping_dict(shopping_list): standard_dict=init_dict() for key in shopping_list: standard_dict[key]=1 return standard_dict
另一个对比案例
如果说Python是存储参数值供后续调用而非使用默认值,以下代码应输出1和2,但实际输出1和1:
def test(a=0): a+=1 return a print(test()) print(test())
原因解释
核心逻辑是Python的默认参数只会在函数定义时计算一次,而非每次调用函数时重新生成:
- 可变对象(如字典、列表):当
init_dict()作为默认参数时,函数定义阶段就会执行该函数生成一个字典对象,后续所有未传standard_dict的调用都会复用这个同一个字典实例。第一次调用修改了它的键值对,第二次调用自然会读取到修改后的状态。 - 不可变对象(如整数、字符串):
test(a=0)中的0是不可变类型,a +=1并不会修改原来的默认参数0,而是创建一个新的整数对象(值为1)并赋值给局部变量a。每次调用时,默认参数都是最初的0,所以每次调用都会得到1。
总结
如果需要每次调用函数时都生成全新的默认对象,绝对不能将可变对象直接设为默认参数,正确的做法是在函数内部完成初始化,确保每次调用都能拿到独立的新对象,避免状态泄露。
内容的提问来源于stack exchange,提问作者mitikawa
相关产品推荐
相关产品推荐

