python解释器剖析及其安装
概述
- py解释器 = py编译器 + py虚拟机
python解释器安装
- https://www.python.org/ftp/python/ 可以看到各个版本的python解释器的源码包、安装包。源码包是不区分架构的(arm和x86),在对于平台编译安装就行。
- 下载源码包后,三板斧安装
./configure [--prefix=PREFIX] # 选择安装路径,默认是/usr/local
make
make install
py代码编译和代码对象
- py编译器会将py代码编译为py字节码。但实际情况是编译成一个代码对象 code object(在C中的表示)。
- 代码对象 code object 是一段可执行的 Python 代码在 CPython 中的内部表示。
可执行的 Python 代码包括:- 函数
- 模块(py文件)
- 类
- 生成器表达式
代码对象 code object的结构
- 参考:Python 中的代码对象 code object 与 code 属性
- 代码块对象的属性可以在python中通过函数名.__code__属性获取到0.0。且对应的python中的类型为<class ‘code’>。在Cpython中对应为PyCodeObject对象。
- compile方法
- python内置的compile方法可以将py字符串形式的代码编译成<class ‘code’>对象。
with open("./test_module.py", "r") as f: source = f.read() obj = compile(source, "./test_moudle.py", "exec")
主要属性
- co_argcount
- 函数接收参数的个数,不包括 *args 和 **kwargs 以及强制关键字参数。
- co_code
- 二进制格式的字节码 bytecode,以字节串 bytes 的形式存储(在 Python 2 中以 str 类型存储)。它为虚拟机提供一系列的指令。函数从第一条指令开始执行,在碰到 RETURN_VALUE 指令的时候停止执行。
- co_cellvars
- co_cellvars 元组里面存储着所有被嵌套函数用到的变量名。
- co_freevars
- co_freevars 元组里面存储着所有被函数使用的在闭包作用域中定义的变量名。
- co_cellvars 和 co_freevars:这两个属性用来实现嵌套函数的作用域。
- co_consts
- 常量表。在函数中用到的所有常量,比如整数、字符串、布尔值等等。它会被 LOAD_CONST 操作码使用,该操作码需要一个索引值作为参数,指明需要从 co_consts 元组中加载哪一个元素。
- co_consts 元组的第一个元素是函数的文档字符串 docstring,如果没有则为 None。
- co_filename
- 代码对象所在的文件名。
- co_firstlineno
- 代码对象的第一行位于所在文件的行号。
- co_flags
- 这是一个整数,存放着函数的组合布尔标志位。
- 比如:如果函数中使用了yield指令,co_flags & CO_GENERATOR == True。CO_GENERATOR = 32。就表明函数时一个生成器函数。用来指引运行时去创建生成器对象。
- co_lnotab
- 这个属性是 line number table 行号表的缩写。它以字节串 bytes 的形式存储,每两个字节是一对,分别是 co_code 字节串的偏移量和 Python 行号的偏移量。
- co_kwonlyargcount
- 存放强制关键字参数的个数。在 Python 2 中则没有这个属性。
- co_name
- 是与代码对象关联的对象的名字,如果是函数,就是函数名,类就是类名咯。
- co_names
- 模块局部变量符号表。该属性是由字符串组成的元组,里面按照使用顺序存放了(模块的局部变量)全局变量和被导入的名字。
- co_nlocals
- 函数中局部变量的个数,相当于是 co_varnames 的长度。
- co_stacksize
- 一个整数,代表函数会使用的最大栈空间。
- co_varnames
- 函数局部变量符号表。函数所有的局部变量名称(包括函数参数)组成的元组。首先是位置参数、默认参数和强制关键字参数,然后是 *args 和 **kwargs(如果有的话)。最后是按照第一次使用顺序排列的其他局部变量。
查看字节码
- dis:字节码反汇编器
- dis.dis(myfunc):返回出myfunc函数的字节码的可读实现形式
- dis.dis(<class ‘code’>类型):返回出code对象对应的字节码的可读实现形式
- 使用指令反汇编一个py文件
- python3 -m dis 3.p
.pyc文件
- .pyc文件是python编译的代码对象的二进制存储在该文件中。作为编译结果的缓存,提高下次运行效率。
- Python逆向(二)—— pyc文件结构分析
python操作码
查看python中的操作码
import opcode
for i in opcode.opname:
print(i)
dis查看操作码名称
dis.opname[100]
python虚拟机运行时相关数据结构
PyFrameObject对象 栈帧
- Python的Frame对象
- 在python中的类型为<class ‘frame’>。在cpython中对应为PyFrameObject对象。是python虚拟机的运行上下文,也被称为python调用栈。
- 调用栈 call stack 是运行 Python 程序的主要结构。它为每个当前活动的函数调用创建一个东西 —— “帧 frame”,也叫栈帧,调用栈的栈底是程序的入口点。每个函数调用推送一个新的帧到调用栈,每当函数调用返回后,这个帧被销毁。
- 在python中可使⽤ sys._getframe(0)或inspect.currentframe() 获取当前堆栈帧。
Frame主要属性
- clear
- f_back:前一个堆栈帧(朝向调用者),如果这是底部堆栈帧则为None
- f_builtins:内建对象
- f_code:在这个框架中执行的Code对象
- f_globals:用于全局变量
- f_lasti:字节码指针。给出精确的指令(这是代码对象的字节码字符串的索引)
- f_lineno:与当前字节码指令对应的源码⾏号
- f_locals:用于查找局部变量的字典
- f_trace:记录当前栈帧的异常信息
- f_trace_lines
- f_trace_opcodes
python运行时的名称空间
- 就是搜索符号(变量)的空间。python的一个运行Frame有三个名称空间
- builtins、globals、locals。变量名搜索优先级:locals > globals > builtins
- locals:当前帧的局部变量。
- dir()不加参数默认打印局部变量。也可使用locals()函数查看
- globals:当前帧的全局变量(帧外部的变量)。
- globals()函数查看
- builtins:python内建变量。
python数据栈和块栈
- Python 解释器和三种栈
- 数据栈 data stack
- 在每个帧中,有一个数据栈 data stack(也称为计算栈 evaluation stack)。数据栈就是 Python 函数运行的地方,运行的 Python 代码大多数是由推入到这个栈中的内容组成的,解释器操作它们,然后在函数返回后销毁它们。
- 可见python的计算、存取值等操作是通过栈实现的。python虚拟机是基于栈的虚拟机。(与之对应的是基于寄存器的虚拟机)。
- 块栈 block stack
- 在每个帧中,还有一个块栈 block stack 。它被 Python 用于跟踪某些类型的控制结构:循环、try / except 块以及 with 块,将语句块全部推入到块栈中,当退出这些控制结构时,块栈被销毁。这将帮助 Python 了解任意给定时刻哪个块是活动的,例如 continue 或者 break 语句可能影响块的运行。
PyFunctionObject 函数对象
- 构造函数对象、类对象时使用。
- 构建函数是使用MAKE_FUNCTION指令,通过code object去创建一个函数对象。
- 创建类时是使用LOAD_BUILD_CLASS指令,其实是使用python内建函数__build_class__去将函数变为一个类0.0。
主要属性
typedef struct {
PyObject_HEAD
PyObject *func_code; /* A code object */
PyObject *func_globals; /* A dictionary (other mappings won't do) */
PyObject *func_defaults; /* NULL or a tuple */
PyObject *func_closure; /* NULL or a tuple of cell objects */
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_name; /* The __name__ attribute, a string object */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
} PyFunctionObject;
Cell对象
- 用来实现函数闭包的对象。
python虚拟机的类机制
python中一切皆对象。类也是一种对象,所以描述起来容易混乱。为了方便描述,把python对象分层两种。
1、class对象
- 可以用于实例化对象的对象(类)。
2、instance对象
- 被别的class对象实例化出来的对象。
对象之间的关系
is-kind-of
- 子类和父类之间的关系。继承关系
- python内置方法issubclass()可判断
- 对象的__bases__属性记录了类型对象的父类们
is-instance-of
- 实例和类之间的关系
- python内置方法isinstanceof()可判断
- 另外内置type()方法可以直接打印出实例的类型
- 对象的__class__属性记录了对象的类(类型)
一个对象可能是两种类型
- python中有两个特殊的对象:type, object。
- type对象,是所有类的类型(包括它自己)。所有类型对象 isinstanceof type。
- object对象又是所有对象的父类(不包括它自己)。所有对象 issubclass object
- 所以这两个对象之间的关系
- type isinstanceof type;type issubclass object
- object isinstanceof type;over(object没有父类了)
- 所以其他对象的关系
- int isinstanceof type;int issubclass object
- 自定义对象:MyClass isinstanceof type; MyClass issubclass object
- 自定义对象的实例 ins isinstanceof MyClass、object; over
- 所以类型对象是属于这两种类型的。
MISC
globals()和__builtins__
- py的内建对象会被默认导入vm的globals()。
- globals()[“__builtins__”]可查看内建对象。
讲CPython解释器的
byterun一个教学的py解释器
- GitHub上有byterun源码。可以下载参考。
原文地址:https://blog.csdn.net/qq_37264095/article/details/136305368
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!