实习发生在代码即
'a'*4096编译时。通常,编译时会导致以下字节码:
0 LOAD_ConST 1 ('a') 2 LOAD_ConST 2 (4096) 4 BINARY_MULTIPLY但是,由于两者都是常量,因此可以
BINARY_MULTIPLY在窥视孔优化器的编译时执行常量折叠,这发生在
fold_binop:
static intfold_binop(expr_ty node, PyArena *arena, int optimize){ ... PyObject *newval; switch (node->v.BinOp.op) { ... case Mult: newval = safe_multiply(lv, rv); break; case Div: ... } return make_const(node, newval, arena);}如果
safe_multiply可以求值,则将结果添加到中的常量列表中
make_const,如果
safe_multiply返回
NULL,则什么也没有发生-
无法执行优化。
safe_multiply
仅在结果字符串不大于4096个字符时执行:
#define MAX_STR_SIZE 4096 static PyObject *safe_multiply(PyObject *v, PyObject *w){ ... else if (PyLong_Check(v) && (PyUnipre_Check(w) || PyBytes_Check(w))) { Py_ssize_t size = PyUnipre_Check(w) ? PyUnipre_GET_LENGTH(w) : PyBytes_GET_SIZE(w); if (size) { long n = PyLong_AsLong(v); if (n < 0 || n > MAX_STR_SIZE / size) { //HERE IS THE CHECK! return NULL; } } } ...}现在,在
PyCode_New以下位置创建代码对象后,所有字符串常量都将被插入:
PyCodeObject *PyCode_New(..., PyObject *consts,...){ ... intern_string_constants(consts); ...因此
'a'*4096变得被拘禁而
'a'*4097不是被拘禁,对于第一种情况,优化的字节码现在是:
0 LOAD_ConST 3 ('aaaaaaaaa...aaaaaaaaaaa')看起来这是负责任的提交,并且这是相应的bug。
自Python3.7起,行为已发生变化-在Python3.6中,限制仍然为20。
在旧版本中,执行了产品,然后检查结果的大小小于21:
static intfold_binop(expr_ty node, PyArena *arena){ ... PyObject *newval; switch (node->v.BinOp.op) { ... case Mult: newval = PyNumber_Multiply(lv, rv); break; ... default: // Unknown operator return 1; } Py_ssize_t size = PyObject_Size(newval); if (size == -1) { ... } else if (size > 20) { //HERE IS THE CHECK OF SIZE Py_DECREF(newval); return 1; } ...至于为什么以前的值是
20现在的值,
4096我只能推测。但是
4096,对于现代机器上的unipre对象来说,听起来并不算多,尽管这
20是所有类的门槛,不仅是unipre。



