编译原理实战课
宫文学
北京原点代码 CEO
26066 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
真实编译器解析篇 (19讲)
编译原理实战课
15
15
1.0x
00:00/00:00
登录|注册

19 | Python编译器(三):运行时机制

add魔术方法
tp_call属性
可调用性
long_add函数
binaryfunc类型
PyNumberMethods
dir()函数
类型名称
PyLong_Type
自定义类型
用C语言实现
魔术方法
插槽
类型信息
唯一ID
基于引用计数的垃圾收集机制
基于堆
定长的数据和变长的数据
减少常量对象的引用计数
设置a的值为该常量
获取保存了所有本地变量的字典
弹出上一步存进去的常量对象
从名称表里取出变量名称
栈里放的数据是对象指针
对象的引用数
常量1在Python内部是一个对象
一课一思
Python运行时的特征
对象的创建和初始化过程
元类(metaclass)
类型对象的tp_call函数
自定义类的示例
Callable协议
数值计算协议
类型对象的设计
Python内置类型
PyTypeObject
Python对象的特点
PyObject和PyVarObject
STORE_NAME指令
LOAD_CONST指令
参考资料
课程小结
Python对象的创建
Python对象的一些协议
Python的类型系统
Python对象的设计
字节码的执行过程
Python运行时机制

该思维导图由 AI 生成,仅供参考

你好,我是宫文学。
在前面两讲中,我们已经分析了 Python 从开始编译到生成字节码的机制。但是,我们对 Python 只是了解了一半,还有很多问题需要解答。比如:Python 字节码是如何运行的呢?它是如何管理程序所用到的数据的?它的类型体系是如何设计的,有什么特点?等等。
所以今天这一讲,我们就来讨论一下 Python 的运行时机制。其中的核心,是 Python 对象机制的设计
我们先来研究一下字节码的运行机制。你会发现,它跟 Python 的对象机制密切相关。

理解字节码的执行过程

我们用 GDB 跟踪执行一个简单的示例程序,它只有一行:“a=1”。
这行代码对应的字节码如下。其中,前两行指令实现了“a=1”的功能(后两行是根据 Python 的规定,在执行完一个模块之后,缺省返回一个 None 值)。
你需要在 _PyEval_EvalFrameDefault() 函数这里设置一个断点,在这里实际解释指令并执行。
首先是执行第一行指令,LOAD_CONST。
你会看到,解释器做了三件事情:
从常数表里取出 0 号常数。你知道,编译完毕以后会形成 PyCodeObject,而在这个对象里会记录所有的常量、符号名称、本地变量等信息。常量 1 就是从它的常量表中取出来的。
把对象引用值加 1。对象引用跟垃圾收集机制相关。
把这个常数对象入栈。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了Python的运行时机制和对象设计,重点讨论了字节码的执行过程和Python对象的设计。通过GDB跟踪执行示例程序,详细解读了LOAD_CONST和STORE_NAME指令的执行过程,揭示了Python程序中的任何符号都是对象的特点。此外,文章介绍了Python对象的设计思路,包括基于堆的内存申请、基于引用计数的垃圾收集机制以及对象的唯一ID。通过对Python对象的设计特点的阐述,读者可以深入了解Python的类型系统设计。文章还介绍了Python的类型系统设计,每个PyObject对象都有一个类型信息,保存类型信息的数据结构是PyTypeObject。PyTypeObject本身也是一个PyObject,包含了对一个类型的各种描述信息,也包含了一些函数的指针,用于实现各种标准操作。Python的类型系统设计相当精巧,为Python语言的很多优点提供了基础支持。整体而言,本文通过深入浅出的方式,为读者呈现了Python运行时机制和对象设计的核心要点,为进一步深入学习Python编译器提供了重要的基础知识。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(4)

  • 最新
  • 精选
  • xiaobang
    请问pypy内部也有类似的pytype结构吗

    作者回复: 你比较喜欢PyPy?这很好。PyPy这个项目有很多创新思维,很有启发性。如果把PyPy研究透,能够大大促进对编译工作的实质的理解。 回答一下你的问题:PyPy做编译的思路,跟CPython是不同的。CPython更多是解释执行,类型信息是在运行时动态根据py_type字段去查找,然后再基于类型信息去执行正确的操作。所有这些动作都是运行时去做的,所以开销很大。 而PyPy更像是v8编译器、Julia编译器。它会在编译时进行类型推理,从而确定出每个变量的类型,并确定出正确的操作。所以,它不需要这么个py_type字段,用来在运行时做类型的查找。也因此,PyPy编译出来的对象,对象头里顶多有为了垃圾收集而保留的引用计数的字段。 这里其实有个隐藏的问题:并不是所有类型信息都是可以在编译期推理出来的,所以肯定也需要运行时的分派机制(runtime dispatch),这跟Java、C++语言都是一样的。我们本课程讲到面向对象语言的实现的时候,会提到这个知识点。 对PyPy实现机制的理解,可以参考这篇论文:PyPy’s Approach to Virtual Machine Constructionhttps://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.207.4675&rep=rep1&type=pdf 在学习了本课程多个编译器以后,你可以把不同编译器对比着来理解。对于Python语言而言,因为存在多个编译器,每个编译器的实现思路又迥然不同,所以就更有助于开拓思维。

    2020-09-18
    4
  • 维李设论
    python也是万物皆对象?堆那里跟js有点儿像啊,比js的能力更多了,是不是解释性脚本语言都是这个特点?

    作者回复: 解释型的语言是一个很宽泛的划分,其实都是解释性的语言的话,其实现机制也会有很大的不同。 首先,解释型语言并不是不编译,它其实也有一个编译过程,就像CPython会编译成字节码。 但每种语言的编译程度可能会不同。比如,同样是Python语言的编译器,PyPy就会进行类型推理,从而得到执行符合该数据类型的动作,并避免或减少在解释执行时才去查询对象的类型。这样的话,对象的内存结构也会有不同的设计。

    2020-08-22
    1
  • coconut
    你可以注意到,我在图 1 中标出了每个字段所占内存的大小,总共是 28 个字节 这里没看懂,图上标的不是32个字节么?

    作者回复: 非常感谢,你挑出了一个内容不一致的地方。 这里ob_digit应该是4个字节的32位整数的数组。

    2021-01-14
  • 飞翔
    python编译过程中会调到python的代码,pgen用来生成c语言的代码,那这个原始的Python编译器是用什么实现的?也就是第一个的Python编译器是怎么出来的?
    2020-07-17
    1
收起评论
显示
设置
留言
4
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部