Python中没有给需要传入参数的函数传参会发生什么?这个问题可能很多人都没有想过,因为我们在设计和使用程序的时候通常不会这么做,而我思考这个问题也是来源于一个师兄给我发的Festo开发者网站的登陆问题,代码很简答。
def func(par=[]):
par.append("a")
return par
print(len(func()+func()+func()))
第一直觉输出是3,但是当我写代码验证的时候发现事情没有那么简单,代码结果是7!!!
想不通,输出三个返回的列表相加后的结果看看:
>>print(func()+func()+func())
['a', 'a', 'a', 'a', 'a', 'a', 'a']
果然没错,列表里面包含7个元素,但是func()函数的确只被调用了三次。
想不到什么原因,查一波资料没有找到解释,自己用最笨的方法找原因吧。
首先单步调试看看发生了什么:
第一次调用func()的时候par的初始值为:[],返回值为:['a'],没错;第二次的时候par的初始值为:['a'],返回值为:['a','a'];第三次的时候par的初始值为:['a','a'],返回值为:['a','a','a']。
看起来是后一次的函数把前一次的返回值作为参数传入了,为什么会这么做呢,调用的时候分明没有传入任何参数。
开始从内存的角度分析问题,怀疑三次调用读写的是同一块内存,在函数中打印一下变量的地址看看:
def func(par=[]):
print(id(par))
par.append("a")
return par
print(func()+func()+func())
运行结果为:
2676459528776
2676459528776
2676459528776
['a', 'a', 'a', 'a', 'a', 'a', 'a']
三次调用中传入局部变量par的地址都是一样的,说明每次调用都会操作同一块内存,没调用一次func()函数,都会往这块内存中写入一个'a'。刚刚说到第一次调用返回['a'],第二次返回['a','a'],第三次返回值['a','a','a']。按理说三次的和应该是6个a,但是程序输出确是7个a,这里又该如何解释。
回到最初的问题:
func()+func()+func()
我们知道“+”是一个双目运算符,两边必须有左值和右值,上式中的func()返回的是par可以看做是一个“指针A”(Python中可变对象是通过“指针”进行传递的),这个“指针A”指向的内存中保存的内容是['a'],这个“指针A”所指向的内容就作为第一个“+”号的左值。前面说到三次调用func()操作的都是同一块内存,所以第二次调用func()的时候往这块内存中又写入了一个'a',内容变为['a','a'],这个时候“指针A”所指向的内容也是['a','a'](因为指向的是同一块内存)。因此前面两个func()+func()运行时的结果是['a','a']+['a','a']==['a','a','a','a'],“+”号返回的是一个新的临时变量,会开辟一个新的内存空间来进行保存。第三次调用func()的时候内存中的值变为['a','a','a'],再加上前面两个的和['a','a','a','a'],结果就是7个‘a’啦。
如果我们事先给一个左值,再加上后面三个func(),结果肯定是6个'a',程序验证一下:
def func(par=[]):
print(id(par))
par.append("a")
return par
print([]+func()+func()+func())
说明以上分析正确。
总结一下:
在Python中如果一个函数设置有可变参数,而我们在调用时没有传入参数,那么Python就会自动分配一个变量作为该函数的参数。