Python 为什么';t1和x2B;1使用二进制代码添加?

Python 为什么';t1和x2B;1使用二进制代码添加?,python,python-2.7,python-internals,Python,Python 2.7,Python Internals,我这样做: >>> dis.dis(lambda: 1 + 1) 0 LOAD_CONST 2 (2) 3 RETURN_VALUE 我期待一个二进制的加法操作码来执行加法。如何计算总和?Python解释器从内到外进行解释,也就是说,它读取1+1并将其计算为2,然后创建一个函数对象,返回常量2(注意这里的顺序!)。最后,dis函数进行计算。新创建的lambda函数对象,它只返回一个2 因此,在创建lambda函数对象时,1+1已经被计算出来,并且dis.dis(

我这样做:

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

我期待一个二进制的加法操作码来执行加法。如何计算总和?

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

因此,在创建lambda函数对象时,
1+1
已经被计算出来,并且
dis.dis()
函数对解释器读取
1+1
并将其计算为
2
时发生的加法一无所知

如果您执行以下操作:

>>> dis.dis(lambda: x + 1)
  1           0 LOAD_GLOBAL              0 (x)
              3 LOAD_CONST               1 (1)
              6 BINARY_ADD          
              7 RETURN_VALUE  

您会注意到,使用了二进制添加指令,因为
x+1
本身无法进一步简化。

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

引述

/*在常量上折叠二进制操作。
加载常数c1加载常数c2 BINOP-->加载常数BINOP(c1,c2)*/
案例二元功率:
大小写二进制乘法:
大小写二进制\u真\u除:
案例二元\u楼层\u划分:
大小写二进制_模:
案例二元化添加:
大小写二进制_减法:
案例二元逻辑推理:
案例二元换档:
案例二元换档:
案例单元和:
大小写二进制异或:
案例二元或:
如果(lastlc>=2&&
ISBASICBLOCK(i-6、7号区块)&&
折叠常数(&codestr[i-6],常数)){
i-=2;
断言(codestr[i]==LOAD_CONST);
cumlc=1;
}
打破
基本上,它寻找这样的指令

LOAD_CONST c1
LOAD_CONST c2
BINARY_OPERATION
并对其求值,并用结果和
LOAD\u CONST
指令替换这些指令。引用

/*更换负载常数c1。荷载常数c2 BINOP
带荷载常数binop(c1,c2)
consts表必须仍然是列表形式,以便
可以附加新常量。
使用指向第一个加载常量的codestr调用。
如果折叠失败(即1+'a'),则放弃转换。
如果新常量是序列,则仅当大小
低于阈值。防止pyc文件从
在出现如下代码时变大:(无,)*1000。
*/
这个特定代码的实际评估发生了

case BINARY\u添加:
newconst=PyNumber_Add(v,w);
打破

但是
dis.dis(compile('1+1',''eval'))的输出也是
LOAD\u CONST(2)RETURN\u VALUE
。这里没有由内而外,是吗?这里没有口译;这是一个非常简单的编译时优化。就目前而言,答案意味着比Python目前所做的要聪明得多。+1我猜也在做类似的事情。值得一提的是,
BINARY_DIVIDE
在Python2中是一个例外(正如PyPy源代码中的注释所解释的)。