Skip to main content
 首页 » 编程设计

函数内定义的 Python 编译器和常量

2025年05月04日13落叶无声

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