Python中一切皆对象,包括函数,函数的参数是函数对象的一个属性(这个属性仍然是一个对象)。 函数及其默认参数在定义(执行函数的def语句)时被初始化,且只被初始化一次。
调用函数时,传递的是参数对象的地址,下面的代码演示了不论参数是否为可变对象, 形式参数和实际参数的地址是完全一致的:
def immutable(pb):
print('id of pb: %s' % id(pb))
pb += 1
print('id of pb: %s' % id(pb))
print('value of pb: %d' % pb)
def mutable(pb):
print('id of pb: %s' % id(pb))
pb.append(1)
print('id of pb: %s' % id(pb))
print('value of pb: %s' % pb)
b = 1
b2 = b
print('id of b: %s' % id(b))
immutable(b)
print('id of b: %s' % id(b))
print('value of b: %d' % b)
print('value of b2: %d' % b)
mb = [1]
mb2 = mb
print('id of mb: %s' % id(mb))
mutable(mb)
print('id of mb: %s' % id(mb))
print('value of mb: %s' % mb)
print('value of mb2: %s' % mb2)
这种机制导致当函数使用可变对象作为默认参数时,且调用函数时使用可变对象, 前面的调用会影响后面的调用,因为前面的调用修改了默认参数的值:
def default_param_emplist(b=[]):
print('param before modified: %s' % b)
b += [1]
print('param after modified: %s' % b)
default_param_emplist([3])
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist([3])
print(default_param_emplist.__defaults__)
print('-----------------')
def default_param_none(b=None):
print('param before modified: %s' % b)
b = b or []
b += [1]
print('param after modified: %s' % b)
default_param_none([3])
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none([3])
print(default_param_none.__defaults__)
print('-----------------')
def no_default_param(b: str):
print('param before modified: %s' % b)
b += [1]
print('param after modified: %s' % b)
no_default_param([3.1])
print(no_default_param.__defaults__)
no_default_param([3.2])
print(no_default_param.__defaults__)
解决这个问题的方法:不要用可变对象作为参数的默认值, 必须使用复合型数据作为参数值时,可以用tuple等不可变对象, 在函数体里根据该参数的类型判断如何处理。
Ref: