当前位置: 首页 > 后端技术 > Python

Python变量类型作为函数默认参数的副作用

时间:2023-03-26 12:51:33 Python

在Python中定义函数时,可以为其指定默认参数,这样就不用每次调用函数时都传递参数,你的代码可以简化。在定义函数时,如果使用变量类型作为函数的默认参数,往往会产生一些副作用。看看下面的一段代码。deffoo(li=[]):li.append(1)print(li)foo()foo()foo()你可能期望得到如下结果:[1][1][1]但实际上,结果是Yes:[1][1,1][1,1,1]从结果来看,好像每次调用这个函数,li列表记录的都是上次调用的结果,并没有使用默认参数[]。但是当我们每次调用函数时都传递一个空列表[],就不会产生副作用,可以正确得到我们想要的结果。deffoo(li=[]):li.append(1)print(li)foo([])foo([])foo([])[1][1][1]为什么会这样?其实造成这个问题的原因是Python中函数的特性决定的。由于函数也是对象,对象可以有自己的属性,函数也有自己的属性。创建foo函数时,其默认参数存储在其__defaults__属性中。该函数只会创建一次,以后每次执行foo()时,只会调用该函数,不会重新创建一个函数。所以函数的默认参数只会计算一次,无论后面调用多少次,默认参数永远是同一个对象。我们可以通过id()函数打印出默认参数的内存地址来查看。deffoo(li=[]):li.append(1)print(li,id(li))foo()foo()foo()[1]48904632[1,1]48904632[1,1,1]48904632可以看出,调用函数3次后,内部打印的li地址是一样的,所以其实是同一个对象。既然您知道了问题的原因,那么如果可以解决它呢?我们可以使用None作为函数的默认参数。在调用foo函数时,我们可以通过判断函数体内li是否为None来判断是否需要使用默认值。这样,在调用foo()函数时,不传递任何参数时,只要给li赋一个默认值即可。deffoo(li=None):ifliisNone:li=[]li.append(1)print(li)foo()foo()foo()[1][1][1]改变的副作用type作为函数的默认参数,不需要每次调用foo函数都传一个参数,可以很好的解决这个问题。因此,当我们为函数定义默认参数时,我们应该尽量使用不可变类型,以避免意想不到的副作用。当然,除非你清楚地知道你需要利用可变类型的特性来达到某些目的。