在Python开发中,有一个看似简单却经常让开发者(包括有经验的开发者)栽跟头的陷阱——可变默认参数。这个陷阱如此常见,以至于它几乎成了Python面试的经典题目之一。然而,即使我们知道了这个问题的存在,在实际编码中仍然可能不经意间再次踩坑。
本文将从原理层面深入剖析这个陷阱,通过具体的代码示例展示问题所在,探讨Python内部的工作机制如何导致这种现象,并提供几种可靠的解决方案。最后,我们还会讨论一些相关的设计哲学和最佳实践。
2. 深入原理:Python的函数定义机制
要理解这个问题,我们需要了解Python如何处理函数定义和默认参数:
- 函数定义的执行时机:在Python中,函数定义是一个可执行语句。当解释器遇到
def语句时,它会执行这个语句来创建函数对象。 - 默认参数的评估:函数的默认参数值是在函数定义时(即模块加载时)被评估并绑定到函数对象的。这意味着默认参数的值只在函数定义时计算一次,而不是每次调用时都重新计算。
- 可变对象的特性:当默认参数是一个可变对象(如列表、字典等)时,所有对该函数的调用都将共享同一个对象作为默认值。
在之前的例子中:
target=[]是在函数定义时求值的- 创建的空列表对象被绑定到函数对象的
__defaults__属性中 - 每次调用使用默认值时都引用同一个列表对象