5

来自 Perl 背景,我习惯于:

my @words = qw(fee fi fo fum);

我想知道以下 Python 是否会导致运行时性能下降:

words = 'fee fi fo fum'.split()

或者 ifwords在编译时绑定。

4

2 回答 2

5

dis您可以使用该模块查看字节码:

>>> from dis import dis
>>>
>>> def f():
...     words = 'fee fi fo fum'.split()
... 
>>> dis(f)
  2           0 LOAD_CONST               1 ('fee fi fo fum')
              3 LOAD_ATTR                0 (split)
              6 CALL_FUNCTION            0
              9 STORE_FAST               0 (words)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE 

split(由 加载LOAD_ATTR)被调用 via并在运行时CALL_FUNCTION将其结果分配给wordsvia 。STORE_FAST换句话说,x.split()即使x是硬编码的字符串,也不会在编译时解析。

当然, using'fee fi fo fum'.split()和它的结果之间的性能差异,即['fee', 'fi', 'fo', 'fum'],将可以忽略不计,所以不要仅仅为了性能提升而从一个更改为另一个。

于 2013-08-16T17:33:25.480 回答
3

即使在 PERL 中也不能在编译时绑定它,因为每次通过该语句时都必须创建一个新的新列表。

换句话说,在 Python 中,当你看到

x = ['fee', 'fi', 'fo', 'fum']

代码不能只加载特定的对象地址,x因为每次执行语句时它都必须是一个新的新列表对象。考虑

def foo():
    return ['fee', 'fi', 'fo', 'fum']

x = foo()
x[0] = 'bar'

print foo()[0]   # must be 'fee'
print x[0]       # must be 'bar'

然而,Python 对不可变对象做了一些优化;例如:

def foo():
    return (1, 2, 3)

实际上总是返回同一个对象(它不会每次都分配一个新的元组),并且对于

def foo():
    return 3 * 4

它实际上返回 12 而不在运行时进行乘法运算。

但是,您的示例无法解决加载在编译时计算的常量,它必须至少是一个列表“文字”(这实际上是一个列表生成器,每次评估时都会创建一个新对象)。

IIRC 常量折叠仅在编译时针对数字/字符串上的二进制运算符进行,而不是针对任何函数调用(请注意,在 Python 中,即使是不好的做法,更改例如标准函数也是合法的len,所以你不能确定len("foo")总是返回 3)。

仅传递常量的标准字符串上的方法调用确实可以在编译时移动 IMO,但 AFAIK 目前还没有完成(而且这并不常见,因此可能不值得付出努力)。

于 2013-08-16T17:46:44.097 回答