本系列作为本人@takooctopus深入学习python机制的记录,这个博客遵照着栖迟于一丘的博客上面的流程进行的,也包含我在实际查看源码时的感想,特此列出,表示感谢。
Python字节码
我们知道Python虚拟机的实现机制是基于栈结构的,Cpython会使用三种类型的栈:
-
调用栈
call stack
。这是运行Python
程序的主要结构。它为每个当前活动的函数调用使用了一个东西 —— “帧frame
”,栈底是程序的入口点。每个函数调用推送一个新的帧到调用栈,每当函数调用返回后,这个帧被销毁。 -
在每个帧中,有一个计算栈
evaluation stack
(也称为数据栈data stack
)。这个栈就是 Python 函数运行的地方,运行的 Python 代码大多数是由推入到这个栈中的东西组成的,操作它们,然后在返回后销毁它们。 -
在每个帧中,还有一个块栈
block stack
。它被 Python 用于去跟踪某些类型的控制结构:循环、try / except
块、以及with
块,全部推入到块栈中,当你退出这些控制结构时,块栈被销毁。这将帮助 Python 了解任意给定时刻哪个块是活动的,比如,一个continu
e 或者break
语句可能影响正确的块。
我们在[Include/opcode.h]
中能找到关于这些字节码的定义:
{{- code -}}
上面就是定义的几乎全部操作字节码了。
因为有些指令需要参数,所以定义了HAVE_ARGUMENT
这个作为分界,没有参数的指令在它上面,编码小于它「90」,有参数的指令编码大于「90」
{{- code -}}
而任何代码域对象在函数中可以以属性__code__
来访问其PyCodeObject
中的属性。
Pyc文件的反编译
系统自带的函数 dis.dis()
将反汇编一个函数、方法、类、模块、编译过的 Python 代码对象、或者字符串包含的源代码,以及显示出一个人类可读的版本。
举例来说
{{- code -}}
{{- code -}}
话说Python3.6之后,每条字节码不管有没有参数都占两字节,其中字节码指令和参数各占一字节了。