编译:代码编程生成可执行文件,可执行文件不跨平台和架构,一次编译多次运行
狭义上的编译是指从源码到机器码的过程,编译器比如GCC,MSVC
广义上的编译是从一种代码到另一种代码(中间代码)
解释:无需编译直接执行,但是解释器不跨架构和平台
虽然Python是一种解释性的语言,但实际上是先将Python代码编译成字节码(byte code),然后再执行,编译和解释执行都是使用CPython。编译过程与C语言的编译过程比较类似:
每一个函数有一个code object,保存了函数的很多信息,其中co_code字段中保存了虚拟机指令的二进制表示(即byte code),将code object写入二进制文件(即.pyc文件)。
程序运行时,code object保存再内存的PyCodeObject对象中,当程序运行结束时,将code object写入到.pyc文件中,下一次运行相同的程序时,Python会根据.pyc文件中的code object直接建立内存中的PyCodeObject对象,无需重新编译。
code object中byte code是二进制表示,反编译后可阅读,比如
include/opcode.h中共有121个opcode,CPython解释器中有一个很大的循环,不停读入opcode执行对应的指令,对应的指令使用C实现,比如
在源代码编译成PyCodeObject对象后,就有虚拟机负责剩下的运行,虚拟机会从PyCodeObject中读取byte code(Python虚拟机指令,不是CPU指令),并在当前上下文中执行,但是PyCodeObject中不包含程序执行时所需的动态信息(上下文信息),程序运行的动态信息包含在frame中。
每次调用函数或者刚开始运行Python时,会建立一个新的frame(可以这么理解,但是CPython存在优化,比如惰性对象),并在这个frame环境下一条一条运行byte code,每一条byte code有相应的C语言代码执行。frame是一个栈结构,但是实现是用链表实现的,该frame记录了返回地址和pc值等关键值。
编译器和解释器的区别
深入理解Python虚拟机
Python Internal
CPython Internals
码农高天:不基础的python基础