一、问题描述:
例如,定义一个函数,传入一个list,添加一个end再返回:
def add_end(l=[]):
l.append('end')
return l
1、不使用默认参数调用时,
print add_end([1, 2])
运行结果如下:
[1, 2, 'end']
没有问题。
2、使用默认参数时,
print add_end()
print add_end()
运行结果如下:
['end']
['end', 'end']
可见,第一次调用时返回结果正确,第二次调用时返回结果错误。
二、错因分析:
首先明确,默认参数也是一个变量,python函数在定义的时候,默认参数l的值就被计算出来了,它存储一个空列表[ ]的内存地址(注:python使用引用语义,即python变量保存的是值的引用,采用这种方式,变量所需的存储空间大小一致,因为变量只是保存了一个引用),即它指向空列表[ ],默认参数l存储的这个内存地址不会在该函数被调用的时候再被计算。
调用该函数时若使用默认参数,会对默认参数进行修改,而实际修改的是默认参数指向的列表,默认参数L中存储的仍然是该列表的内存地址。第一次使用默认参数后默认参数指向的列表已经不再为空。
简而言之,就是默认参数的值在定义的时候被计算,调用的时候不会再次被计算。所以每一次函数调用对默认参数的修改都会影响下一次函数调用。
三、解决办法
使默认参数指向不变对象。例如:
def add_end2(l=None):
if l is None:
l = []
l.append('end')
return l
使用默认参数:
print add_end()
print add_end()
运行结果如下:
['end']
['end']
python不变对象是指该对象在内存中的值不能被改变。当改变某个变量的值时,由于该变量指向的值为不可变对象,会在内存中重新开辟一个新的地址,存储新的值,然后将变量指向这个新的值。原来的内存中的值并不会发生变化。python不变类型包括数值类型(int和float)、字符串(string)、元组(tuple)、None。
python可变对象即该对象在内存中的值可以被改变。变量改变后,实际其所指向的值直接发生改变。python可变类型包括列表(list)、字典(dict)、集合(set)。
设计不可变对象的好处:
1、不变对象一旦创建,其内部的数据就不能修改,这样就减少了由于修改数据导致的错误。
2、由于对象不变,在多任务环境下同时读取不变对象不需要加锁。若对象可变,在多任务环境下读取对象时必须加锁,以防止在读取过程中其它任务对变量进行修改。
牢记:使默认参数指向不变对象。
参考:
网友评论