Python 编译器是否识别在函数中定义的常量,以便它只计算一次它们的值,而不管该函数随后在代码中被调用多少次?
例如,
def f():
x = [ 1, 2, 3, 4 ]
# stuff
for i in range( 100 ):
f()
x 是否会在 f() 被调用 100 次后重新计算?
并非总是可以在使用常量的函数之外定义常量,我很好奇 Python 是否支持您处理这些情况。
请您参考如下方法:
(注意这适用于 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
如您所见,整数文字是常量,但每次都必须构建列表。
这是一个相对较快的操作(可能比查找全局还要快,但时间仍然可以忽略不计)
如果您有一个使用元组的函数 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
但这似乎是一个过早优化的案例。
为函数存储的常量可以作为 function.__code__.co_consts 找到。
>>> g.__code__.co_consts
(None, 1, 2, 3, 4, (1, 2, 3, 4))
之所以每次都必须建立一个新的列表,是因为如果列表发生变化,它不会影响每次加载的列表。
如果它不是常量列表,元组优化就会消失。
>>> 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
