自学内容网 自学内容网

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文件

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)!