[python]一个关于默认参数的老问题和一个有关优化的新问题

一个老问题:

 def func(defau=[]):
defau.append(1)
return defau print(func())#print[1]
print(func())#print[1,1]
print(func())#print[1,1,1]

学python时候应该都遇到过这个问题,为什么?一般的说法是把这个可变的默认参数和函数绑定在一块了

但是,怎么绑定的???

python文档[1],里面对def的解释:

A function definition is an executable statement. Its execution binds the function name in the current local namespace to a function object .

一个可执行的声明,在现有的名称空间中把函数名字和函数对象绑定在一块了。

也就是说,这种绑定只有在def声明执行的时候才会发生,只有在def语句执行的时候,才会把函数名字和一个新的函数对象绑定在一块[2]。

那么,这些和默认参数有什么关系?

这默认参数的关系就是,只有当这种绑定发生的时候,默认参数才会得到赋值,换句话说,只有在def声明执行的时候,默认参数所引用的对象才会和函数对象结合起来。

所以,在上面的例子中,因为def语句只执行了一次,所以几次调用函数func其实都是执行的同一个函数对象,使用的同一个list:

 def func(defau=[]):
defau.append(1)
return defau print(id(func()))#print 1756350390856
print(id(func()))#print 1756350390856
print(id(func()))#print 1756350390856

看大神laike9m的博客[3]的时候,发现其实可以利用这一点对python的性能进行优化的。

我们都知道,python中名称的查找顺序为LEGB,也就是local->enclosing->global->builtin,如果我们把一个全局变量赋值给一个函数的默认参数,把一个全局变量变为一个函数的局部变量,那么在查找链中,就不用进行到global,直接在local域中就可以得到需要的变量了:

 import timeit
setup1="""
import math
def cal():
math.sin(1)+math.cos(1)
"""
setup2="""
import math
def cal2(sin=math.sin,cos=math.cos):
sin(1)+cos(1)
"""
t1=timeit.Timer(setup1,"print('setup1')")
t2=timeit.Timer(setup2,"print('setup2')")
print(t1.timeit(100))
print(t2.timeit(100))
#setup1
#0.0003371067712671346
#setup2
#8.921092541729796e-05

可以看到,在执行100遍的情况下,运行时间相差一个量级

参考资料:[1]python 文档

     [2]Default parameter values in python

[3]pythony优化函数执行的技巧

上一篇:如果不能显示真正的考验个别车型toast问题解决


下一篇:windows下nginx直接处理静态文件