Python编译/解释过程

我试图更清楚地了解Python编译器/解释器的过程。 不幸的是,我还没有在翻译课上课,也没有多读这些课。

基本上,我现在明白的是,.py文件中的Python代码首先被编译成python字节码(我认为它是偶尔看到的.pyc文件)。 接下来,字节码被编译成机器代码,这是处理器实际理解的一种语言。 很多,我读过这个线程为什么Python解释之前编译源代码字节码?

有人能够对我的整个过程给予一个很好的解释,记住我对编译器/解释器的知识几乎是不存在的? 或者,如果这是不可能的,也许给我一些资源,快速浏览编译器/口译?

谢谢

字节码实际上不是解释为机器码,除非你使用了一些奇特的实现,如pypy。

除此之外,你有正确的描述。 字节码被加载到Python运行库中并由虚拟机解释,虚拟机是读取字节码中每条指令的代码片段,并执行指定的任何操作。 您可以使用dis模块查看这个字节码,如下所示:

 >>> def fib(n): return n if n < 2 else fib(n - 2) + fib(n - 1) ... >>> fib(10) 55 >>> import dis >>> dis.dis(fib) 1 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (2) 6 COMPARE_OP 0 (<) 9 JUMP_IF_FALSE 5 (to 17) 12 POP_TOP 13 LOAD_FAST 0 (n) 16 RETURN_VALUE >> 17 POP_TOP 18 LOAD_GLOBAL 0 (fib) 21 LOAD_FAST 0 (n) 24 LOAD_CONST 1 (2) 27 BINARY_SUBTRACT 28 CALL_FUNCTION 1 31 LOAD_GLOBAL 0 (fib) 34 LOAD_FAST 0 (n) 37 LOAD_CONST 2 (1) 40 BINARY_SUBTRACT 41 CALL_FUNCTION 1 44 BINARY_ADD 45 RETURN_VALUE >>> 

详细的解释

理解上面的代码永远不会被CPU执行是非常重要的。 也没有被转换成(至less,不是Python的官方C实现)。 CPU执行虚拟机代码,执行由字节码指令指示的工作。 当解释者想要执行fib函数时,它会一次一个地读取指令,并按照他们的要求去做。 它查看第一条指令LOAD_FAST 0 ,从而从参数被保存的地方抓取参数0( n传递给fib )并将其推送到解释器的堆栈(Python的解释器是堆栈机器)。 在读取下一条指令LOAD_CONST 1 ,它从函数拥有的常量集合中获取常数1,在这种情况下恰好是数字2,并将其推入堆栈。 你可以看到这些常量:

 >>> fib.func_code.co_consts (None, 2, 1) 

下一条指令COMPARE_OP 0告诉解释器popup两个最上面的堆栈元素,并在它们之间进行不等式比较,将布尔结果推回堆栈。 第四条指令根据布尔值判断是跳转五条指令还是继续下一条指令。 所有这些措辞都解释了if n < 2的条件expression式在fib 。 这将是一个非常有益的练习,你梳理其余的fib字节码的含义和行为。 唯一一个我不确定的是POP_TOP ; 我猜JUMP_IF_FALSE被定义为将其布尔参数留在堆栈而不是popup它,所以它必须显式popup。

更有意义的是检查fib的原始字节码:

 >>> code = fib.func_code.co_code >>> code '|\x00\x00d\x01\x00j\x00\x00o\x05\x00\x01|\x00\x00S\x01t\x00\x00|\x00\x00d\x01\x00\x18\x83\x01\x00t\x00\x00|\x00\x00d\x02\x00\x18\x83\x01\x00\x17S' >>> import opcode >>> op = code[0] >>> op '|' >>> op = ord(op) >>> op 124 >>> opcode.opname[op] 'LOAD_FAST' >>> 

因此你可以看到字节码的第一个字节是LOAD_FAST指令。 下一对字节'\x00\x00' (16位中的数字0)是LOAD_FAST的参数,并告诉字节码解释器将参数0加载到堆栈上。