Jet*_*lue 1 python performance compiler-optimization
Python编译器是否可以识别在函数中定义的常量,这样,无论随后在代码中调用该函数多少次,它仅计算一次它们的值?
例如,
def f():
x = [ 1, 2, 3, 4 ]
# stuff
for i in range( 100 ):
f()
Run Code Online (Sandbox Code Playgroud)
会x重新计算100次f()调用吗?
并非总是可以在使用常量的函数之外定义常量,我很好奇Python是否在这种情况下得到了支持。
简短的回答:对于列表来说,则不然。
如果我们用 编译后检查中间代码dis,我们会看到:
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 LOAD_CONST 3 (3)
9 LOAD_CONST 4 (4)
12 BUILD_LIST 4
15 STORE_FAST 0 (x)
18 LOAD_CONST 0 (None)
21 RETURN_VALUERun Code Online (Sandbox Code Playgroud)
正如您所看到的,程序首先将常量加载1到4堆栈上并将它们压入堆栈,然后用这些常量构造一个列表,这意味着它每次都会构造一个列表。
如果列表没有发生变化,我建议在函数外部定义常量:
some_constant = [1, 2, 3, 4]
def f():
# use some_constant
# ...
pass
Run Code Online (Sandbox Code Playgroud)
(请注意,这适用于CPython,在其他实现中可能有所不同)
Python代码被解析并编译为字节码。您可以查看dis模块使用的说明。
>>> def f(x):
... x = [1, 2, 3, 4]
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_CONST 4 (4)
8 BUILD_LIST 4
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
>>> print(dis.Bytecode(f).info())
Name: f
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
4: 4
Variable names:
0: x
Run Code Online (Sandbox Code Playgroud)
如您所见,整数文字是常量,但是列表每次都必须构建。
这是一个相对较快的操作(可能比查找全局操作更快,但时间仍然可以忽略不计)
如果您有g使用元组代替的函数,则将其作为常量加载:
>>> def g(x):
... x = (1, 2, 3, 4)
>>> dis.dis(g)
2 0 LOAD_CONST 5 ((1, 2, 3, 4))
2 STORE_FAST 0 (x)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
>>> print(dis.Bytecode(g).info())
Name: g
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
4: 4
5: (1, 2, 3, 4)
Variable names:
0: x
Run Code Online (Sandbox Code Playgroud)
但这似乎是过早优化的情况。
为函数存储的常数可以找到function.__code__.co_consts。
>>> g.__code__.co_consts
(None, 1, 2, 3, 4, (1, 2, 3, 4))
Run Code Online (Sandbox Code Playgroud)
每次都必须构建一个新列表的原因是,以便在更改列表时,它不会影响每次加载的列表。
如果不是常量列表,则元组优化就会消失。
>>> def h(x):
... x = (1, 2, 3, x)
>>> dis.dis(h)
2 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_FAST 0 (x)
8 BUILD_TUPLE 4
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
>>> print(dis.Bytecode(h).info())
Name: h
Filename: <stdin>
Argument count: 1
Kw-only arguments: 0
Number of locals: 1
Stack size: 4
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
0: None
1: 1
2: 2
3: 3
Variable names:
0: x
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
488 次 |
| 最近记录: |