我正试图通过使用timeit测试(计时)各种函数来优化一些python代码。
我发现,根据变量是关键字参数还是函数内的变量,我得到了不同的速度。
即:
def test_function(A = value()):
#rest of function....
返回的结果与不同
def test_function():
A = value()
#rest of function ...
我本以为他们会有非常相似的结果——我猜我不理解/错过了一些东西。。。
(也为测试做了10000个循环)
关键字参数在函数定义时求值一次。因此,在您的第一个示例中,value()
只被调用一次,无论您多久调用一次测试函数。如果value()
非常昂贵,这就解释了两个版本在运行时的差异。
没有理由期望您的两个函数做相同的事情,更不用说具有相同的性能特征了。
def test_function(A = value()):
#rest of function....
此函数没有"关键字参数";根本不存在这样的事情。它有一个具有默认值的参数。任何函数的任何参数(除了一些顽固的内置函数)都可以通过关键字或位置传递,但参数本质上不是"关键字参数"。
关键字参数和默认值之间的唯一关联是,当多个参数具有默认值时,向后面的参数提供显式值,同时接受前面参数的默认值的唯一方法是按关键字传递后面的参数。
这两个函数之间的巨大区别在于,当您为A
声明一个默认值时,它是一个默认的值,而不是一些代码,如果没有提供显式值,则每次都会重新生成该值。当你这么说的时候:
def test_function(A = value()):
#rest of function....
您正在为A
设置默认的值。与任何其他上下文一样,当您提供一个复杂的表达式,其中Python需要一个值时,Python将评估该表达式,然后使用结果值。因此,当您在函数定义时设置A
的默认值时,它将被设置为value()
当时返回的任何值。那么这一个值就是A
的默认值。
def test_function():
A = value()
#rest of function ...
在该函数中,每次调用函数时都会对value()
进行求值。因此,如果value()
价格昂贵,那么这个版本将比第一个版本花费更长的时间。但是,如果value()
返回一个稍后发生变化的对象,那么默认的参数版本将始终使用一个对象,无论它在调用函数时处于什么状态,而第二个版本每次都将构造一个新的value
。您使用的版本应该由您希望程序具有的语义决定。
有人讨论为什么这种方法不是确定方法有效性的最佳方法,但如果您使用dis
检查函数的字节码,您可以看到它们是以不同的方式构建的,即t1
在定义时评估其默认参数,因此不需要在随后的函数调用中重新定义:
>>> import dis
>>> def t1(A=1):
... pass
>>> def t2():
.... A=1
>>> dis.dis(t1)
2 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
>>> dis.dis(t2)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (A)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE