我看到有一个变量对象传递给Python函数参数的默认值来加速斐波那契函数的递归。代码如下:deffib(n,cache={0:0,1:1}):如果n不在缓存中:cache[n]=fib(n-1)+fib(n-2)returncache[n]不是很新奇,这个其实是可以的,速度真的很快,运行结果如下:不过,我劝你不要这样做,IDE也会提醒你这样不好这样做:这是因为万物皆对象,Python函数也是对象。默认值是对象的属性。参数的默认值在编译阶段就已经绑定到函数上了。如果它是一个可变对象,Python函数参数的默认值将被存储并由所有调用者共享。也就是说,如果一个函数参数的默认值是一个可变对象,比如List、Dict,调用者A修改了它,那么调用者B调用后看到的就是A修改后的结果。这样的模式往往会产生意想不到的结果结果,如上面fib的算法,只是多了一个bug。你可以看看这个简单的代码:deffunc(n,li=[]):foriinrange(n):li.append(i)print(l)func(2)#[0,1]func(3,l=[1,2])#[1,2,0,1,2]func(2)#[0,1]你可以先估计这段代码的输出,如果和注释一样,那你错了。正确的结果是:[0,1][1,2,0,1,2][0,1,0,1]你可能会想,为什么最后一个func(2)是这样的,别着急,让我们打印(id(li))Debug:deffunc(n,li=[]):print(id(li))foriinrange(n):li.append(i)print(li)func(2)func(3,li=[1,2])func(2)结果如下:140670243756736[0,1]140670265684928[1,2,0,1,2]140670243756736[0,1,0,1]第一个func(2)和第二个func(2)的id相同,说明他们用的是同一个li,也就是说参数的默认值是变量对象的逻辑,对于所有的调用者在其他话,是共享的。如果你想深究为什么Python是这样设计的,可以移步http://cenalulu.github.io/python/default-mutable-arguments/如何避免?最好的方法是不要使用可变对象作为函数默认值。如果一定要这样使用,下面是一个解决方案:defgenerate_new_list_with(my_list=None,element=None):ifmy_listisNone:my_list=[]my_list.append(element)returnmy_list这样,如果my_list的默认值总是Bothare[]。最后,我认为fib函数的实现可能会给您留下深刻印象,但请注意,这种用法非常危险,不应在您自己的代码中使用。
