add by zhj: 文章写的很好,其实只要默认参数在函数中只读不写,那默认值就不会被修改,可变类型作默认参数就不会有问题app
方法二中,当result is None时,修改result的指向,再也不指向默认参数对象,而是赋值一个新的对象。以下,能够看到,result的id变化了函数
In [4]: def f(p=None, q=[]): ...: print id(p), id(q) ...: if p is None: ...: p = [] ...: print id(p) ...: In [5]: f() 9568656 140309648126608 140309648094632 In [6]: f() 9568656 140309648126608 140309648074944
原文:https://blog.csdn.net/sinat_38068807/article/details/85677419测试
说明:默认参数值在函数被定义时已经计算出来,而不是在程序运行时。Python 程spa
序员常常犯的一个错误是把可变的数据类型(例如列表或者字典)看成默认参数值.net
在下面的例子中,函数 buggy() 在每次调用时,添加参数 arg 到一个空的列表 result ,然
后打印输出一个单值列表。可是存在一个问题:只有在第一次调用时列表是空的,第二次
调用时就会存在以前调用的返回值code
def buggy(arg, result=[]): result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b') # 指望获得 ['b']
执行结果:对象
--------1-------- ['a'] --------2-------- ['a', 'b']
1.默认参数值在函数被定义时已经计算出来,而不是在程序运行时blog
2.只要函数调用时没有传递新的列表来覆盖默认参数列表,函数就会使用定义时的那个列表,而且操做依次叠加get
3.上面两次调用中,都没有传递新的列表,程序会调用定义函数时保存的默认参数,并在上一次的基础上进行操做叠加,即:列表在append的时候会在 result原来的基础上append追加值,因此会产生以上结果.class
咱们经过打印列表的ID进行辨识来看看:
def buggy(arg, result=[]): print(id(result)) result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b') # expect ['b']
结果:
--------1-------- 12205768 ['a'] --------2-------- 12205768 ['a', 'b']
咱们会发现ID值是相同的;
说明两次执行时使用的都是开始定义函数时的默认参数 ,进行了操做叠加
4.下面咱们传递新的列表看看:
def buggy(arg, result=[]): print(id(result)) result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b', []) # 传递了新的列表
结果:
--------1-------- 18497224 ['a'] --------2-------- 18504648 ['b']
发现,列表id不一样,而且获得了咱们指望的值
方法1
# 若是写成下面的样子就会解决刚才的问题: def works(arg): result = [] result.append(arg) print(result) works('a') works('b')
结果:
['a'] ['b']
方法2:
# 这样的修改也为了代表是第一次调用跳过一些操做: def nonbuggy(arg, result=None): if result is None: result = [] result.append(arg) print(result) nonbuggy('a') nonbuggy('b')
结果:
['a'] ['b']