用dis.dis反编译一个只有一行return x+1的函数,看CPython 3.14把这行代码拆成了哪些指令,字面量又是怎么被处理的。
Python源码不是直接被解释器执行的,中间先编译成一份字节码。
代码def add_one(x): return x + 1 import dis dis.dis(add_one)
的反编译输出。
dis.dis输出 5 RESUME 0 6 LOAD_FAST_BORROW 0 (x) LOAD_SMALL_INT 1 BINARY_OP 0 (+) RETURN_VALUE
拆解:RESUME 是函数开始执行时的一个占位指令(给解释器插桩用);LOAD_FAST_BORROW 从局部变量槽里取出参数x("Borrow"表示这次取值不需要增加引用计数,是Python 3.14里对LOAD_FAST的一种优化);LOAD_SMALL_INT 把字面量1推入栈——这条指令本身就很说明问题。
按常理,字面量应该存在co_consts里,用LOAD_CONST取出来。
结果add_one.__code__.co_consts = (1,) add_one.__code__.co_names = () add_one.__code__.co_stacksize = 2 add_one.__code__.co_nlocals = 1
co_consts里确实还留着(1,)这个元组,但字节码里用的是 LOAD_SMALL_INT 而不是 LOAD_CONST 0 (1)——这是较新CPython版本做的一项优化:对于能装进一个机器字的小整数,解释器会用专门的LOAD_SMALL_INT指令直接把整数值编码在指令参数里,运行时不用再去co_consts元组里做一次索引查找,省下一次的内存访问。co_stacksize=2 说明这4条指令执行过程中,操作数栈最多同时压了2个值(x和1);co_nlocals=1 对应只有一个局部变量x。
每一步都是本文上面用dis模块跑出来的原始结果。
dis.dis / __code__.co_consts:反编译并检查字节码与常量表