Python默认参数求值机制疑问:可变与不可变参数表现为何不同?
Python默认参数的运行机制解惑:可变与不可变对象的差异
Python的默认参数有个关键特性:它是在函数定义的时候就完成初始化绑定的,不是每次调用函数时重新创建。这也是你两个例子出现不同结果的核心原因,再结合可变/不可变对象的行为差异就能完全理清:
第一个例子:可变对象(列表)作为默认参数
函数fun1定义时,L=[]就已经创建了一个空列表对象,并且把这个对象绑定为L的默认值。每次调用fun1如果没有传入自定义的L,就会直接复用这个已经存在的列表对象。
而L.append(a)是原地修改这个列表对象——没有重新给L赋值,只是在原对象上添加元素。所以每次调用都会在同一个列表上累积内容,最终出现[1]→[1,2]→[1,2,3]的结果。
你可以加一行代码验证对象的唯一性:
def fun1(a, L=[]): print(id(L)) # 打印对象的内存地址 L.append(a) return L print(fun1(1)) print(fun1(2)) print(fun1(3))
输出会显示三次打印的id完全相同,说明每次用的都是同一个列表对象。
第二个例子:不可变对象(整数)作为默认参数
函数g定义时,b=1绑定了整数对象1。整数属于不可变对象——你无法修改一个整数对象本身的值,只能创建新的整数对象。
当执行b = a + b时,a+b计算出的2是一个全新的整数对象,然后函数内的局部变量b被重新绑定到这个新对象上。但这个操作完全没碰过最初默认参数绑定的那个1对象,下次调用函数时,默认参数依然会使用定义时绑定的1,所以每次调用g(1)都会得到2,不会累积。
同样可以用id验证:
def g(a, b=1): print("初始b的id:", id(b)) b = a + b print("赋值后b的id:", id(b)) return b g(1) g(1)
输出会显示两次调用的初始b的id相同(都是1的地址),赋值后的id是新的(2的地址),但不影响默认参数的绑定。
总结
- 可变对象(列表、字典等)作为默认参数时,原地修改会改变共享的默认对象,导致多次调用结果累积。
- 不可变对象(整数、字符串、元组等)作为默认参数时,重新赋值只会改变局部变量的绑定,默认参数始终是定义时的初始对象,不会被修改。
内容的提问来源于stack exchange,提问作者Mezzoforte
相关产品推荐
相关产品推荐

