![864b73db0de8659c33215de20ee3830f.png](https://i-blog.csdnimg.cn/blog_migrate/c94c409dc4ce5d228a7e01d897ce25ff.jpeg)
最终 Python 的执行过程,实际上就是 Python VM 对 ByteCode 的解释过程。程序的三种基本结构:
- 顺序
- 条件
- 循环
数学上已经证明,这三种结构可以表述任意逻辑。Python 也不例外,ByteCode 中也必定实现了这三种结构。
顺序执行
顺序执行是最朴素的一种,CodeObject 就是 ByteCode 在 Frame 中的表示,我们可以通过反汇编对应的 pyc 文件,获得 “汇编代码”,CodeObject、ByteCode、pyc 文件这三种形式表达的是同一个逻辑。
CodeObject 的实现与 C 语言的 char [] 数组类似,一个个字节码顺序排开,Python VM 中通过一个超大的 while 循环,逐个读取这些指令,并一一执行。
以最简单的两行代码为例:
a
预先安装 xdis 模块后,使用可以先将代码编译为 pyc 文件,再反汇编得到汇编代码。那么字节码等效于下面:
![a3a7aa734f75055d9a6afd27e50b086c.png](https://i-blog.csdnimg.cn/blog_migrate/abc811658930e13369b41f9c280909ad.png)
刚好实践一下 65 节的内容。
正式的 Python 代码不太可能这么短,对应的字节码也会长的多,但它们没有本质的区别。
下面就需要 Python VM 出场了,首先通过 1、2 指令,在局部变量字典中创建了 "a" -> 1 的关联,然后将读取的指针 + 1,读取下一条指令,创建 "b" -> 2 的关联。最后的加载的常量 None 和 RETURN_VALUE 指令是 Python 自动为 module 增加的返回值 None,希望你还记得 Python 将 py 文件处理为 module 这回事。
Python 通过不断将读取指针调整到相邻的下一个位置,自然的实现了顺序执行。
《源码解析》对这一部分展开较多,但在逻辑上反而简单的多。
条件执行
Python 中的条件语句主要通过 if 语句实现, 完整的 if 语句有以下几部分:
- 条件判断语句;
- True 时执行的指令;
- False 时执行的指令;
其中条件判断语句不再展开,它的结果只可能在运行栈中只会留下一个 boolean 或者与之等效的对象。
条件执行的 True 和 False 基本上可以认为是两个顺序执行的单元,当然这块可以嵌套其他更复杂的结构,我们暂时不考虑它们。转换成流程图是这样:
![7e893e4499591caa6456d83ad6661a2c.png](https://i-blog.csdnimg.cn/blog_migrate/af0ffc5bd4c10a2cfffbe344d027d23f.jpeg)
我们知道 ByteCode 实际上是一个连续的线形序列,不能像流程图中这样出现两个并列的代码块,我们来做一点位置调整,把它们挤压到一条线上:
![ab97eb2aeb297d4ce69dfb8ad65c6eb7.png](https://i-blog.csdnimg.cn/blog_migrate/4db5cc8224fe0535679f475573c05511.png)
如果你仔细观察,上面的图实际上与最初的流程图是等效的,只是对位置稍作调整。
好,下面让我们看一下简单 if 语句是如何实现的:
if
下面是与之对应的汇编代码:
#
注意:
- 0 加载待判断的 boolean 对象到运行栈,这里我直接指定为 True;
- 2 根据栈中(也就是上一步加载的对象),如果为 False 就跳转到标号 10,否则什么也做,继续下一指令;
- 4、6 实现了 a = 1;
- 8 跳转出 if 语句,这是一个无条件跳转,只要执行到 8 就一定会跳转到 14,相当于 C 中的 goto 语句;
- 10、12 类似,实现了 a = 2;
- 14、16 已经在 if 语句之外,是 module 的返回值。
让我们把汇编的路径绘制出来:
![6e48f849ebacb0d36fc799f45411c342.png](https://i-blog.csdnimg.cn/blog_migrate/58f16f49d22a57f305fa75fce5d6e783.jpeg)
为了便于识别,我将汇编代码的路径和流程图放在一起,并且将:
- 对应单元间隔着色,
- 跳转路径与对应跳转语句着色。
我相信你可以一眼看出汇编代码是如何与流程图对应起来了!
总结
从字节码的角度看, Python VM 在相当大程度上可以认为是一个 “软 CPU”,基本预计的实现与硬件 CPU 的汇编如出一辙。今天一口气介绍了两种基本执行结构。下一步我们要了解循环的实现。
在 x86 等常见 CPU 架构下,循环是通过对 “条件跳转” 指令的精巧安排实现的,很少在 CPU 层面实现专门用于循环的机器指令,Python 作为一种高级抽象语言,它的特殊性在循环的实现上体现出来了,它采用了一种更抽象的实现方式。
让我们拭目以待!
关注公众号 “江川Go”,了解程序员的烧脑日常。
![c455d9f9764c5815d2c7ea34259fea43.png](https://i-blog.csdnimg.cn/blog_migrate/29e7c65ba079bd14917da76b384bfad0.jpeg)