Python函数参数默认值内存机制疑问:为何列表默认值会保留修改?
问题重现
def a(l=[]): print(l) l.append('something') a() # [] a() # ['something']
第一次调用函数a后,直觉上会认为局部变量l和它绑定的列表对象应该被销毁——毕竟函数执行完局部作用域消失,l这个名称也不存在了,没有引用指向堆里的列表对象,它应该被垃圾回收。
但实际运行结果是:第二次调用a()时,输出的不是空列表,而是['something'],仿佛第一次调用修改了函数本身的默认参数。
原本以为每次调用函数时,默认参数会重新创建,但事实并非如此。核心疑问是:这背后的运行机制是什么?为什么函数没执行时,参数默认值就已经存在内存里?
背后的运行机制
Python里函数的默认参数是在函数定义的时候创建的,而不是每次调用函数时。
当你写下def a(l=[])这行代码时,Python解释器就会创建这个空列表对象,并把它和函数a的默认参数绑定在一起,这个对象会被存在函数对象的__defaults__属性里(你可以直接打印a.__defaults__看到它)。
每次调用a()且不传参数时,Python不会重新创建新的空列表,而是直接复用这个已经存在的列表对象。第一次调用时,你给这个列表添加了元素,第二次调用自然会看到修改后的结果。
至于为什么局部变量l销毁后,列表对象还存在?因为函数a本身的__defaults__属性还引用着这个列表,垃圾回收机制不会回收还有引用的对象,所以它会一直存在,直到函数对象本身被销毁。
正确的写法
如果想每次调用函数时都使用全新的空列表,应该把默认值设为None,然后在函数内部初始化:
def a(l=None): if l is None: l = [] print(l) l.append('something') a() # [] a() # []
这样每次调用a()时,都会在函数内部创建新的空列表,避免了默认参数被复用的问题。
内容的提问来源于stack exchange,提问作者Dmitriy Neledva
相关产品推荐
相关产品推荐

