除了常量折叠优化外,Python还有其它的语法树优化手段。
fold_binop
如果表达式的左值和右值都是常量,那么可以对表达式进行折叠优化。如 1 + 2,可以直接折叠为 3。这个操作是通过调用 PyNumber_Add 函数来实现数值的相加,那么最终的结果就是一个常量。除了加法外,还有减法、乘法、除法、位运算等操作。由于上一篇文章已经介绍了这种折叠优化,这里就不再赘述。
make_const
新的 val 是被计算出来的一个常量,如果 val 为 NULL,则跳过。如果 val 不为空,则需要给 val 分配新的内存,将 val 赋值给 node 的 Constant.value,并将 node 的 kind(类型)设置为 Constant_kind。
make_const 在很多地方都会被调用,如 fold_binop、fold_unaryop、fold_iter、fold_compare、fold_subscr、fold_tuple 等函数中。
static int
make_const(expr_ty node, PyObject *val, PyArena *arena)
{
// Even if no new value was calculated, make_const may still
// need to clear an error (e.g. for division by zero)
if (val == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
return 0;
}
PyErr_Clear();
return 1;
}
if (_PyArena_AddPyObject(arena, val) < 0) {
Py_DECREF(val);
return 0;
}
node->kind = Constant_kind;
node->v.Constant.kind = NULL;
node->v.Constant.value = val;
return 1;
}
fold_unaryop
一元运算操作符的折叠优化,如 not、-、+、~ 等操作符。如果操作数不是常量,那么直接返回。否则,根据操作符的类型,调用对应的函数进行计算。如 not 操作符,调用 unary_not 函数,- 操作符,调用 PyNumber_Negative 函数,+ 操作符,调用 PyNumber_Positive 函数,~ 操作符,调用 PyNumber_Invert 函数。
static int
fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
{
expr_ty arg = node->v.UnaryOp.operand;
if (arg->kind != Constant_kind) {
/* Fold not into comparison */
if (node->v.UnaryOp.op == Not && arg->kind == Compare_kind &&
asdl_seq_LEN(arg->v.Compare.ops) == 1) {
/* Eq and NotEq are often implemented in terms of one another, so
folding not (self == other) into self != other breaks implementation
of !=. Detecting such cases doesn't seem worthwhile.
Python uses </> for 'is subset'/'is superset' operations on sets.
They don't satisfy not folding laws. */
cmpop_ty op = asdl_seq_GET(arg->v.Compare.ops, 0);
switch (op) {
case Is:
op = IsNot;
break;
case IsNot:
op = Is;
break;
case In:
op = NotIn;