不断折叠的具体规则是什么?
我刚刚意识到CPython似乎对待常量表达式,它们表示相同的值,而常量折叠方面却有所不同.例如:
I just realized that CPython seems to treat constant expressions, which represent the same value, differently with respect to constant folding. For example:
>>> 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
对于第二个示例,将应用恒定折叠,而对于第一个示例,则不是两个折叠都表示相同的值.由于似乎也折叠了以下表达式,所以它似乎与指数的值无关,也与结果的大小无关.
For the second example constant folding is applied while for the first it is not though both represent the same value. It doesn't seem to be related to the value of the exponent nor to the magnitude of the result since the following expressions are folded as well:
>>> 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
为什么前两个表达式会被不同地对待,并且更笼统地讲,CPython遵循恒定折叠的具体规则是什么?
Why are the first two expressions treated differently and, more generally, what are the specific rules that CPython follows for constant folding?
经过测试:
$ python3.6 --version
Python 3.6.5 :: Anaconda, Inc.
$ python3.7 --version
Python 3.7.1
对于持续折叠,没有没有规则.只有实现细节.它们以前已经更改,并且将再次更改.
There are no rules for constant folding. There are only implementation details. They have changed before, and they will change again.
哎呀,您甚至不能谈论"Python 3行为"或"Python 3.6行为",因为这些实现细节在3.6. 4 和3.6. 5之间进行了更改..在3.6.4上, 2 ** 66
示例被固定折叠.
Heck, you can't even talk about the "Python 3 behavior", or the "Python 3.6 behavior", because these implementation details changed between 3.6.4 and 3.6.5. On 3.6.4, the 2**66
example gets constant-folded.
就目前而言,没人知道"for now"将持续多久,实现细节是AST优化程序包括一些安全措施,以防止在固定折叠上花费过多的时间或内存. 2 **的安全防护66
或 4 ** 33
是基于LHS中的位数和RHS的值:
For now, and no one knows how long "for now" will last, the implementation details are that the AST optimizer includes safeguards to prevent spending too much time or memory on constant folding. The safeguard for 2**66
or 4**33
is based on the number of bits in the LHS and the value of the RHS:
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;
}
}
MAX_INT_SIZE
早于 #define
d.由于 2
是2位数字,而 4
是一个3位数字,对于 4 ** 33
来说,估计结果的大小较小,因此它通过了校验并变为常数折叠.
MAX_INT_SIZE
is #define
d earlier as 128. Since 2
is a 2-bit number and 4
is a 3-bit number, the estimated result size is smaller for 4**33
, so it passes the check and gets constant-folded.
在Python 3.6.5上,实现细节基本相似,但是这种不断折叠发生在
On Python 3.6.5, the implementation details are mostly similar, but this constant folding happens in the bytecode peephole optimizer instead of the AST optimizer, which doesn't exist on 3.6.5.
在Python 3.6.4上,预检查保护措施不存在.窥孔优化器会舍弃太大的常量对结果进行折算后,得出的阈值与预先检查的结果不同.
On Python 3.6.4, the pre-check safeguard doesn't exist. The peephole optimizer will discard too-large constant-folding results after computing them, which results in different thresholds than the pre-checks.