常量折叠的具体规则是什么?

a_g*_*est 6 python cpython python-3.x constantfolding

我刚刚意识到 CPython 似乎对待常量表达式,它们表示相同的值,在常量折叠方面有所不同。例如:

>>> import dis
>>> dis.dis('2**66')
  1           0 LOAD_CONST               0 (2)
              2 LOAD_CONST               1 (66)
              4 BINARY_POWER
              6 RETURN_VALUE
>>> dis.dis('4**33')
  1           0 LOAD_CONST               2 (73786976294838206464)
              2 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

对于第二个示例,应用了常量折叠,而对于第一个示例,虽然两者表示相同的值,但并非如此。它似乎与指数的值或结果的大小无关,因为以下表达式也被折叠了:

>>> dis.dis('2.0**66')
  1           0 LOAD_CONST               2 (7.378697629483821e+19)
              2 RETURN_VALUE
>>> dis.dis('4**42')
  1           0 LOAD_CONST               2 (19342813113834066795298816)
              2 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

为什么前两个表达式的处理方式不同,更一般地说,CPython 遵循的常量折叠的具体规则是什么?


测试:

$ python3.6 --version
Python 3.6.5 :: Anaconda, Inc.
$ python3.7 --version
Python 3.7.1
Run Code Online (Sandbox Code Playgroud)

use*_*ica 8

有没有规则的常量折叠。只有实现细节。他们之前已经改变了,他们将再次改变。

哎呀,您甚至不能谈论“Python 3 行为”或“Python 3.6 行为”,因为这些实现细节在 3.6 之间发生了变化。4和 3.6。5 . 在 3.6.4 上,2**66示例得到了常量折叠。

目前,没有人知道“现在”会持续多久,实现细节是 AST 优化器包括保护措施,以防止在常量折叠上花费太多时间或内存。对或的保护基于 LHS 中的位数和 RHS 的值:2**664**33

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {
    size_t vbits = _PyLong_NumBits(v);
    size_t wbits = PyLong_AsSize_t(w);
    if (vbits == (size_t)-1 || wbits == (size_t)-1) {
        return NULL;
    }
    if (vbits > MAX_INT_SIZE / wbits) {
        return NULL;
    }
}
Run Code Online (Sandbox Code Playgroud)

MAX_INT_SIZE被#define较早d为1 128由于2是2比特数和4是一个3位的数目,所述估计结果大小是较小的4**33,所以它通过检查并获得恒定折叠。

在 Python 3.6.5 上,实现细节大多相似,但是这种常量折叠发生在字节码窥孔优化器中,而不是 AST 优化器中,而 AST 优化器在 3.6.5 中不存在。

在 Python 3.6.4 上,不存在预检查保护措施。peephole 优化器会在计算后丢弃太大的常量折叠结果,这导致与预检查不同的阈值。