3

我正在尝试通过使用 timeit 测试(计时)各种功能来优化一些 python 代码。

我发现我得到不同的速度取决于变量是关键字参数还是函数内。

那是:

def test_function(A = value()):
    #rest of function....

返回的结果不同于:

def test_function():
    A = value()
    #rest of function ...

我会认为他们会有非常相似的结果 - 我猜我在这里不理解/遗漏了一些东西......

(也为测试做 10,000 个循环)

4

3 回答 3

12

关键字参数在函数定义时评估一次。因此,在您的第一个示例value()中,无论您多久调用一次测试函数,都只调用一次。如果value()是昂贵的,这解释了两个版本之间运行时的差异。

于 2012-11-14T03:58:15.163 回答
4

没有理由期望您的两个函数做同样的事情,更不用说具有相同的性能特征了。

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每次都构造一个新对象. 您使用哪个版本应该由您希望程序具有的语义决定。

于 2012-11-14T04:08:04.937 回答
4

有关于为什么这种方法不是确定方法有效性的最佳方法的讨论,但如果你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        
于 2012-11-14T04:02:35.577 回答