来自Perl背景,我习惯于:
my @words = qw(fee fi fo fum);
Run Code Online (Sandbox Code Playgroud)
我想知道以下Python是否会导致运行时性能下降:
words = 'fee fi fo fum'.split()
Run Code Online (Sandbox Code Playgroud)
或者如果words在编译时绑定.
您可以使用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
Run Code Online (Sandbox Code Playgroud)
split(作为加载方式LOAD_ATTR)被调用via CALL_FUNCTION,其结果在运行时分配给wordsvia STORE_FAST.换句话说,x.split()即使x是硬编码字符串,也不会在编译时解析.
当然,使用'fee fi fo fum'.split()和它的结果之间的性能差异,即['fee', 'fi', 'fo', 'fum']可以忽略不计,所以不要仅仅为了提高性能而从一个改变到另一个.
即使在 PERL 中,它也不能在编译时绑定,因为每次执行该语句时都必须创建一个新的列表。
换句话说,在 Python 中,当你看到
x = ['fee', 'fi', 'fo', 'fum']
Run Code Online (Sandbox Code Playgroud)
代码不能只加载特定的对象地址,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'
Run Code Online (Sandbox Code Playgroud)
然而,Python 对不可变对象做了一些优化;例如:
def foo():
return (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
实际上总是返回相同的对象(它不会每次都分配一个新的元组),并且对于
def foo():
return 3 * 4
Run Code Online (Sandbox Code Playgroud)
它实际上返回 12,而没有在运行时进行乘法。
但是,您的示例无法解析为加载在编译时计算的常量,它必须至少是一个列表“文字”(这实际上是每次评估时创建一个新对象的列表生成器)。
IIRC 常量折叠仅在编译时针对数字/字符串上的二元运算符完成,而不是针对任何函数调用(请注意,在 Python 中,更改标准函数等操作是合法的,即使是不好的做法len,因此您不能确定len("foo")始终返回3)。
对仅传递常量的标准字符串的方法调用在 IMO 中确实可以在编译时移动,但据我所知,目前尚未完成(而且这并不常见,因此可能不值得付出努力)。