为什么1 + 1不使用BINARY_ADD?

时间:2015-01-08 05:27:38

标签: python python-2.7 python-internals

我这样做:

>>> dis.dis(lambda: 1 + 1)
0 LOAD_CONST        2 (2)
3 RETURN_VALUE

我期待BINARY_ADD操作码执行添加。如何计算总和?

2 个答案:

答案 0 :(得分:8)

这是Python的窥孔优化器的工作。它在编译时自身仅使用常量来评估简单操作,并将结果作为常量存储在生成的字节码中。

引自Python 2.7.9 Source code

            /* Fold binary ops on constants.
               LOAD_CONST c1 LOAD_CONST c2 BINOP -->  LOAD_CONST binop(c1,c2) */
        case BINARY_POWER:
        case BINARY_MULTIPLY:
        case BINARY_TRUE_DIVIDE:
        case BINARY_FLOOR_DIVIDE:
        case BINARY_MODULO:
        case BINARY_ADD:
        case BINARY_SUBTRACT:
        case BINARY_SUBSCR:
        case BINARY_LSHIFT:
        case BINARY_RSHIFT:
        case BINARY_AND:
        case BINARY_XOR:
        case BINARY_OR:
            if (lastlc >= 2 &&
                ISBASICBLOCK(blocks, i-6, 7) &&
                fold_binops_on_constants(&codestr[i-6], consts)) {
                i -= 2;
                assert(codestr[i] == LOAD_CONST);
                cumlc = 1;
            }
            break;

基本上,它会查找此类指令

LOAD_CONST c1
LOAD_CONST c2
BINARY_OPERATION

并对其进行评估并用结果和LOAD_CONST指令替换这些指令。引用comment in the fold_binops_on_constants function

/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
   with    LOAD_CONST binop(c1,c2)
   The consts table must still be in list form so that the
   new constant can be appended.
   Called with codestr pointing to the first LOAD_CONST.
   Abandons the transformation if the folding fails (i.e.  1+'a').
   If the new constant is a sequence, only folds when the size
   is below a threshold value.  That keeps pyc files from
   becoming large in the presence of code like:  (None,)*1000.
*/

此特定代码的实际评估发生在in this block

    case BINARY_ADD:
        newconst = PyNumber_Add(v, w);
        break;

答案 1 :(得分:1)

Python解释器从内到外解释,也就是说,它读取1 + 1将其评估为2然后创建一个返回常量{{}的函数对象1}}(注意这里的顺序!)。最后,2函数进行求值。新创建的lambda函数对象,它只返回dis

因此,在创建lambda函数对象时已经计算了2,并且1+1函数对解释器读取dis.dis()并进行评估时发生的添加一无所知它到1+1

如果您执行以下操作:

2

您会注意到使用了BINARY_ADD指令,因为>>> dis.dis(lambda: x + 1) 1 0 LOAD_GLOBAL 0 (x) 3 LOAD_CONST 1 (1) 6 BINARY_ADD 7 RETURN_VALUE 无法自行进一步简化。