Python对象模型之我见
文章目录
阅读条件:
C语言基础,Python对象模型基本了解
前言
在深入学习Python的过程中,不可避免地会接触到这样的概念:
在Python中一切都是对象
这个一切甚至比我想象的还要深入,因为在Python的实现层面也都是用面向对象实现的.那么与对象模型相关的类
,实例
的概念是不是也是用面向对象实现的呢?是的,在Python中,类的定义本身也是一个对象.
从实现层面来看,我认为只要能用一个PyObject*
来指向的结构体都是对象.我认为Python中的对象可以分为以下几类:
- 普通内建类对象,不需要开发者实现,由系统提供的类对象,比如int, list等.
- 特殊内建类对象,不要开发者实现,但是在对象模型中具有特殊功能,其实也就是两个特殊对象,type和object.
- 自定义类对象,开发者实现的类所生成的对象.
- 实例对象,由类对象实例化所生成的对象.
下面我们来分别讲讲这些过程.
示意图
下面这幅是从网上摘抄过来的.也是经典Python对象模型示意图.
三个框分别表示元类,类型,一般对象.其中虚线表示类与实例的关系,实线表示父类与子类的继承关系.
创世纪的三个过程
在Python虚拟机中叱咤风云的往往是一个个实例对象.但是在创造他们之前,我们需要经过漫长的过程.了解这个过程,将极大地帮助我们了解元类.
内建类对象的初始化
在CPython中,所有的内建类对象表现为一个个C语言结构体,而且都是静态初始化的全局变量.所以他们几乎天然就是一个PyObject对象了.为什么说几乎呢?因为还需要对他们进行一点点改造.
这个过程的实现在Objects/typeobject.c
的PyType_Ready
中.这个函数主要完成如下工作:
- 确定本类的基类
- 递归地初始化基类
- 确定本类的类型
- 填充本类的__dict__
- 从基类中的继承
- 将本类加入基类的子类列表
这里面值得关注的是第4步和第5步.在完成了这些工作之后,内建对象的构建就完成了.
我们在多说两句,关于特殊内建对象.object对象是所有类对象的基类,也是第一个被初始化的.而type对象是绝大多数对象的类型对象.
自定义类对象的生成
一个自定义的类对象的生成,要经过几个步骤呢?首先,要准备材料.主要是自定义类的名字,自定义类的基类列表以及自定义类的属性列表.这里变量和方法都可以归为属性.然后,就是调用元类了.主要代码Objects/typeobject.c/type_call
一路追下去.
步骤如下:
- 调用metaclass->ob_type->tp_call,也就是type_call.
- 调用metaclass->tp_new,也就是type_new.
- 调用metaclass->tp_alloc,这个方法type本身没有定义,是从object继承而来,所以是object->tp_alloc.也就是PyType_GenericAlloc.
- 初始化新建的type.为其中的一些域赋值.
- 调用PyType_Ready.
- 调用
fixup_slot_dispatchers
,这个很有意思.是处理重载的关键.如果你覆盖了基类的方法,会在这里实现. - 调用metaclass->tp_init,这个方法同样从object继承,也就是object_init.
实例对象的生成
主要步骤如下:
- 调用class->ob_type->tp_call,一般来讲就是type_call.
- 调用class->tp_new,这个方法是从object继承而来,也就是object_new.我们看到这也是创建类对象和实例对象的主要区别点.
- 调用class->tp_alloc,同样是PyType_GenericAlloc.
- 调用class->tp_init.我们经常定义的
def __init__
就是在这里调用的.
基类和类型在Python中的作用
在弄清楚一系列对象的创建过程后,在更高的维度我是怎么看的呢?
object
是一切类对象的基类,是众基之基.所有对象如果没有重写的话,那么所有对象都会从object
中继承方法.所以object最重要的作用是什么呢?就是把所有类都要具有的方法,抽出来,聚集到一起.这就是object
.
实例是类对象实例化的结果.同一类对象的各个实例之间其实大体相似,区别只是个别属性.而类对象之间的结构也是大体相似的,而元类就是各个类对象的类.
通过重载元类的__new__
,__init__
,我们能够控制类对象的生成.重载__call__
,我们能够控制实例对象的生成.
总结
现在总算基本弄清楚Python的对象模型.这块还是有点复杂的.我这里其实就是自己的小结.更多地内容还是得去看书,看源码.
文章作者 成祎
上次更新 2018-01-14