引言
我们常说 Python 一是门解释型语言,只需要敲下
python code.py
就可以运行编写的代码,而无需使用类似于 javac 或者 gcc 进行编译。那么,Python 解释器是真的一行一行读取 Python 源代码而后执行吗? 实际上,Python 在执行程序时和 Java、C# 一样,都是先将源码进行编译生成字节码,然后由虚拟机进行执行,只不过 Python 解释器把这两步合二为一了而已。
事实上,Python 程序在执行过程中同样需要编译(Compile),编译产生的结果称之为字节码,而后由 Python 虚拟机逐行地执行这些字节码。所以,Python 解释器由两部分组成: 编译器和虚拟机。
上图展示了 Python 程序的执行过程,以及C程序的编译、汇编与链接过程,从该图中可以非常明显地看出 Python 与 C 程序的执行区别。Python 如此设计的原因在于将程序的执行与底层硬件进一步地分离,无需担心程序的编译、汇编以及链接过程,使得 Python 程序相较于 C 程序而言更加易于移植。
一、python解释器是什么
1. 解释性语言和编译性语言
计算机看不懂解释性语言和编译性语言的源代码,计算机只认识二进制指令。所以,想让程序被执行,那么自然要先把源代码转化为二进制指令,也就是机器码(最后有解释)。
那么,在什么时候进行转换呢?
- 有的语言要求必须提前把代码一次性转换完毕,这种就是编译型语言,用的转换工具就叫编译器,比如C语言、C++。
- 有的语言则可以一边执行一边转化,用到哪里了就转哪里,这种就是解释性语言,用的转化工具叫解释器,比如python、javascript。
- java比较特殊,既有编译又有解释。但是编译并没有直接编译成机器码,而是编译成字节码,然后再拿到虚拟机中执行。这种设计初衷是在跨平台的同时兼顾执行效率,这里就不展开了。
2. python解释器
python解释器是一种让其他程序运行起来的程序,编写的python代码必须在解释器中运行,这东东已经在我们安装python的时候都装上了。
所以,现在我print(hello world)
,就可以运行了,控制台可以看到文本的输出。
3. python程序运行过程
上面的一行代码虽然简单,但是python运行它还是经过了两步操作:
- 将源代码编译成为“字节码”
- 转发“字节码”到“虚拟机”
字节码编译
可以理解为翻译,把print(hello world)
翻译成字节码,字节码会保存在后缀名是.pyc的文件里,这文件其实就是编译后的.py源代码。
这些字节码相较于源代码,运行起来速度要快得多。为什么?
- 因为在下一次运行程序时,如果在上次保存了字节码之后没有修改过源代码了,Python就会加载.pyc文件并且跳过编译这个步骤。
- 当必须要重新编译时,python会自动检查源文件和字节码文件的时间戳,如果你又保存了源代码,下次程序运行时,字节码将自动重新创建。
python虚拟机
Python Virtual Machine,简写为PVM,当有字节码文件之后,就会被发送到PVM里来执行。
这里注意,PVM并不是指的一个独立的程序,是不需要安装的。可以把PVM理解为Python的运行引擎,是一个迭代运行字节码指令的大循环,一个个的完成操作,直到结束。
从技术角度看,PVM才是“解释器”的最后一步。
二、关于python的性能
大家都知道,python的缺点是运行慢。但其实这里的慢也只是相对而言,跟C和C++这类编译性语言相比,确实执行速度还不够快。
为什么?
上述也提到了python会把源代码转成字节码,然后再将字节码解释出来。但是为了更好的跨平台性,这里的字节码是一种跟平台无关的格式,所以并不是底层的二进制代码。到目前为止,只要不是对运行速度有严苛要求的领域,比如数值计算或动画这种,经常需要核心处理单元至少以C语言的速度执行,绝大多数的应用,python还是可以胜任的。
相比于缺点,python带来开发效率的提升,还有python良好的生态,相信也是很多人喜爱的的重要因素。
机器码和字节码
机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。
通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。
用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义。手编程序时,程序员得自己处理每条指令和每一数据的存储分配和输入输出,还得记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作,编写程序花费的时间往往是实际运行时间的几十倍或几百倍。而且,编出的程序全是些0和1的指令代码,直观性差,还容易出错。现在,除了计算机生产厂家的专业人员外,绝大多数的程序员已经不再去学习机器语言了。
- 机器语言是微处理器理解和使用的,用于控制它的操作二进制代码。
- 8086到Pentium的机器语言指令长度可以从1字节到13字节。
- 尽管机器语言好像是很复杂的,然而它是有规律的。
- 存在着多至100000种机器语言的指令。这意味着不能把这些种类全部列出来。
总结:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到。
字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。
字节码主要为了实现特定软件运行和软件环境、与硬件环境无关。字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。字节码的典型应用为Java bytecode。
- 字节码在运行时通过JVM(JAVA虚拟机)做一次转换生成机器指令,因此能够更好的跨平台运行。
- 字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。
- 通常情况下它是已经经过编译,但与特定机器码无关。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量、引用、指令等构成的序列。
总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。