为什么Python不优化临时变量?

时间:2015-03-11 17:37:18

标签: python optimization refactoring python-internals

Fowler的Extract Variable重构方法(以前称为Introduce Explaining Variable)表示使用临时变量来使代码更清晰。这个想法是通过引入一个不需要的局部变量来阐明复杂的代码,并将该变量命名为出于展示目的。它还提倡对评论进行这种解释。Other languages优化临时变量,这样就没有时间或空间资源的成本。为什么Python不这样做?

In [3]: def multiple_of_six_fat(n):
   ...:     multiple_of_two = n%2 == 0
   ...:     multiple_of_three = n%3 == 0
   ...:     return multiple_of_two and multiple_of_three
   ...:

In [4]: def multiple_of_six_lean(n):
   ...:     return n%2 == 0 and n%3 == 0
   ...:
In [5]: import dis

In [6]: dis.dis(multiple_of_six_fat)
  2           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (2)
              6 BINARY_MODULO
              7 LOAD_CONST               2 (0)
             10 COMPARE_OP               2 (==)
             13 STORE_FAST               1 (multiple_of_two)

  3          16 LOAD_FAST                0 (n)
             19 LOAD_CONST               3 (3)
             22 BINARY_MODULO
             23 LOAD_CONST               2 (0)
             26 COMPARE_OP               2 (==)
             29 STORE_FAST               2 (multiple_of_three)

  4          32 LOAD_FAST                1 (multiple_of_two)
             35 JUMP_IF_FALSE_OR_POP    41
             38 LOAD_FAST                2 (multiple_of_three)
        >>   41 RETURN_VALUE

In [7]: dis.dis(multiple_of_six_lean)
  2           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (2)
              6 BINARY_MODULO
              7 LOAD_CONST               2 (0)
             10 COMPARE_OP               2 (==)
             13 JUMP_IF_FALSE_OR_POP    29
             16 LOAD_FAST                0 (n)
             19 LOAD_CONST               3 (3)
             22 BINARY_MODULO
             23 LOAD_CONST               2 (0)
             26 COMPARE_OP               2 (==)
        >>   29 RETURN_VALUE

2 个答案:

答案 0 :(得分:10)

因为Python是一种高度动态的语言,引用可以影响行为。

比较以下内容,例如:

>>> id(object()) == id(object())
True
>>> ob1 = object()
>>> ob2 = object()
>>> id(ob1) == id(ob2)
False

如果Python“优化”ob1ob2变量,行为就会发生变化。

Python对象的生命周期由引用计数控制。将weak references添加到混合加线程中,您将看到优化离开变量(甚至是本地变量)可能会导致不良行为更改。

此外,在Python中,从性能角度来看,删除这些变量几乎不会发生任何变化。本地命名空间已经过高度优化(值由数组中的索引查找);如果您担心解除引用局部变量的速度,那么您在项目的时间关键部分使用了错误的编程语言。

答案 1 :(得分:2)

Issue 2181(在函数末尾优化局部变量)有一些有趣的观点:

  • 由于不再符号,它可以使调试更难 存在。 Guido says only do it for -O.
  • 可能会破坏inspectsys._getframe()
  • 的一些用法
  • 更改对象的生命周期。例如,以下示例中的myfunc可能在优化后失败,因为目前Python保证在函数退出之前文件对象未关闭。 (糟糕的风格,但仍然)

    def myfunc():
        f = open('somewhere', 'r')
        fd = f.fileno()
        return os.fstat(fd)
    

    不能改写为:

    def bogus():
        fd = open('somewhere', 'r').fileno()
        # the file is auto-closed here and fd becomes invalid
        return os.fstat(fd)
    
  • 一位核心开发人员表示“它不太可能在实际代码中提供任何加速,我认为我们不应该为编译器增加复杂性。”