Python中函数定义耗时太长

11 投票
3 回答
785 浏览
提问于 2025-04-18 08:20

为什么在定义的时候,Python要计算p的值?这让这个函数的定义变得特别慢。

def f():
    raise Exception('Some error')
    p = 2322111239**42322222334923492304923

print 'Defined!'

另外,如果p的值是在定义时计算的,那为什么定义这个函数的时候没有出错呢?

def f():
    return 4
    p = 11/0

这个例子显然没问题,因为没有涉及常量:

def f():
    raise Exception('Some error')
    x=42322222334923492304923
    p = 2322111239**x

print 'Defined!'

3 个回答

3

我们来试试一个更合理的数字:

>>> def f():
...    p=123**45
... 

如果你使用 dis 来查看字节码,你会发现 p 的值是在函数被调用之前就已经定义好了:

>>> import dis
>>> dis.dis(f)
  2           0 LOAD_CONST               3 (11110408185131956285910790587176451918559153212268021823629073199866111001242743283966127048043)
              3 STORE_FAST               0 (p)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE
7

这个解释器的功能叫做 常量折叠(想了解更多可以看看 这里 的一些有趣信息)。有几个问题讨论了过于激进的常量折叠。类似的问题也可能出现在内存方面,比如分配了很多内存后又直接丢掉了(可以参考 这里)。

8

这是一个叫做“窥视优化器”的东西:

链接到代码

特别要注意第104-106行

case BINARY_POWER:
    newconst = PyNumber_Power(v, w, Py_None);
    break;

它的目的是加快函数的运行速度,虽然在导入模块时定义的速度会慢一些。这个想法是,你只需要编译一次函数的代码,但可能会调用很多次。而且,对于两个常量的指数运算结果是不会改变的,所以每次都重新计算就没必要了。

注意:在Python 3中,常量折叠已经转移到了新的AST优化器中,具体在ast_opt.c里,peephole.c已经不再使用。现在的代码有保护措施,以防止过于激进的优化,这种优化可能会导致解析/编译步骤变得缓慢或占用过多内存,就像这个问题中所展示的那样。

撰写回答