3

因此,当我在页面底部看到此注释时,我正在阅读itertools文档:

请注意,可以通过将全局查找替换为定义为默认值的局部变量来优化上述许多方法。例如,点积配方可以写成:

def dotproduct(vec1, vec2, sum=sum, imap=imap, mul=operator.mul):  
    返回总和(imap(mul,vec1,vec2))

他们这是什么意思?我是否理解将函数添加为输入变量会使程序运行得更快或更有效?

有人可以像 5 岁的孩子一样向我解释这个吗?:-) 提前致谢。

4

3 回答 3

3

Python 效率的一个问题是该语言是完全动态的。例如考虑简单的循环

def myfunc():
    for i in range(10):
        foo(bar(i))

似乎该函数foo将被调用bar十次。然而,函数bar可以例如改变什么foo,而代码foo又可以改变什么bar。因此,Python 被迫在每次迭代时检查foo指向什么以及指向什么bar。这需要查看模块全局变量,如果在内置(预定义)名称中找不到任何内容。在 10 次迭代中的每一次。

所有全局查找都会发生同样的情况(例如,您甚至可以定义一个名为len“隐藏”具有该名称的标准函数的函数)。

当使用局部变量时,事情会更简单

 def myfunc():
     f = foo
     b = bar
     for i in range(10):
         f(b(i))

原因是fandb是局部变量,因此获取能够进行调用的值要简单得多。外部的代码myfunc无法更改fb指向的内容。

因此,获得一些速度的一个技巧是编写类似的东西

def myfunc(x, sin=math.sin):
    ...

这样在使用的时候sin就不用先抬头math再往sin里看math

这是一种微优化,但被认为是不好的风格,除非你真的发现(测量)速度是一个问题,修复已被测量以提供合理的收益,但速度缓慢并不足以严重到需要更多激进的做法。

于 2013-06-28T20:11:58.643 回答
1

有几个好处:

  1. 解析函数定义时计算默认参数。因此,当实际调用该函数时,不需要这样的计算。

  2. 在函数调用期间,当 python 发现在局部范围内找不到变量时,它首先在全局变量中查找它,如果仍然找不到,则转到内置函数。最终,如果在任何地方都找不到变量,它将引发找不到变量的错误。

因此operator.mul将需要三个调用:首先operator在本地范围内搜索,然后在全局范围内搜索。现在因为它在全局范围内现在搜索operator模块中找到mul. 在函数头中声明它mul=operator.mul会将这些搜索次数减少到 1。

看字节码:

局部变量将使用LOAD_FAST.

而其他变量如operator.itemgetter,list并且list需要更多的调用次数。

>>> def dotproduct(vec1, vec2, sum=sum, imap=imap, mul=operator.mul):  
        sum(imap(mul, vec1, vec2))
        list([operator.itemgetter(1) for x in lis])
...     
>>> dis.dis(dotproduct)
  2           0 LOAD_FAST                2 (sum)
              3 LOAD_FAST                3 (imap)
              6 LOAD_FAST                4 (mul)
              9 LOAD_FAST                0 (vec1)
             12 LOAD_FAST                1 (vec2)
             15 CALL_FUNCTION            3
             18 CALL_FUNCTION            1
             21 POP_TOP             

  3          22 LOAD_GLOBAL              0 (list)
             25 BUILD_LIST               0
             28 LOAD_GLOBAL              1 (lis)
             31 GET_ITER            
        >>   32 FOR_ITER                21 (to 56)
             35 STORE_FAST               5 (x)
             38 LOAD_GLOBAL              2 (operator)
             41 LOAD_ATTR                3 (itemgetter)
             44 LOAD_CONST               1 (1)
             47 CALL_FUNCTION            1
             50 LIST_APPEND              2
             53 JUMP_ABSOLUTE           32
        >>   56 CALL_FUNCTION            1
             59 POP_TOP             
             60 LOAD_CONST               0 (None)
             63 RETURN_VALUE  
于 2013-06-28T20:09:58.660 回答
0

让我尝试。

我认为这意味着当 python 将尝试查找变量(函数或其他对象)时,它将使用 LEGB 规则

请检查此问题以获取 LEGB 的完整描述

但是这个技巧允许python在最近的本地范围内找到变量(参数所在的位置)

于 2013-06-28T20:10:28.550 回答