读python源码--对象模型
学python的人都知道,python中一切皆是对象,如class生成的对象是对象,class本身也是对象,int是对象,str是对象,dict是对象...。所以,我很好奇,python是怎样实现这些对象的?带着这份好奇,我决定去看看python的源码,毕竟源码才是满足自己好奇心最直接的方法。
在object.h文件中,定义了两种数据结构PyObject和PyVarObject,代码如下:
#define PyObject_HEAD \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type; #define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; typedef struct _object {
PyObject_HEAD
} PyObject; typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
这两种数据结构分别对应python的两种对象:固定长度对象和可变长度对象。python中的所有对象都属于这两种对象中的一种,如int,float是固定长度对象,list,str,dict是可变长度对象。从上面两种对象数据结构定义来看,可变长度对象和固定长度对象的头都是PyObject结构体,也就是说python中所有对象的开头都包含这个结构体,并且可以用PyObject *指针来访问任何对象,这种访问对象的方法在python的源码中随处可见。PyObject结构体包含两个成员,ob_refcnt和ob_type指针。ob_refcnt用来表示对象被引用的次数,当ob_refcnt == 0时,这个对象会被立即销毁;ob_type指针指向了一个_typeobject类型的结构体,表示对象所属的类型,也就是生成该对象的类型,这其实很类似于面向对象中类与实例的关系,PyObject是某个类的实例,ob_type表示这个类。但与面向对象不同的是,ob_type本身也是个对象,我们来看下_typeobject的定义:
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /*类型名 */
Py_ssize_t tp_basicsize, tp_itemsize; /* 实例化对象的大小 */ /* 标准方法 */ destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
reprfunc tp_repr; /* 标准类(数值类,列表类,dict类)方法*/ PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping; /* 其它标准方法*/ hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
...
} PyTypeObject;
从上面定义来看,_typeobject的开头也包含了PyObject结构体,所以它也是一个对象,既然它也是一个对象,那么按照面向对象的理解,它又是谁来生成的呢?答案是所有PyTypeObject对象都是通过PyType_Type来生成的,包括PyType_Type本身,因为PyType_Type也是PyTypeObject对象,有点绕。PyType_Type的定义是通过将PyType_Type声明为全局静态变量实现的,具体如下:
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, )
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
, /* tp_print */
, /* tp_getattr */
, /* tp_setattr */
, /* tp_compare */
(reprfunc)type_repr, /* tp_repr */
, /* tp_as_number */
, /* tp_as_sequence */
, /* tp_as_mapping */
(hashfunc)_Py_HashPointer, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
, /* tp_as_buffer */
...
}
从PyType_Type定义来看,ob_type被初始化为它自己的地址,所以PyType_Type的类型就是自己。从python源码实现来看,所有PyTypeObject的ob_type都会指向PyType_Type对象,所以PyType_Type是所有类型的类型,称之为元类。python中定义了很多内建的类型对象,如PyInt_Type (int类型),PyStr_Type (str类型),PyDict_Type(dict类型) 类型对象,下面看下PyInt_Type类型的定义:
PyTypeObject PyInt_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, )
"int",
sizeof(PyIntObject),
,
(destructor)int_dealloc, /* tp_dealloc */
(printfunc)int_print, /* tp_print */
, /* tp_getattr */
, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */
(reprfunc)int_to_decimal_string, /* tp_repr */
&int_as_number, /* tp_as_number */
, /* tp_as_sequence */
, /* tp_as_mapping */
(hashfunc)int_hash, /* tp_hash */
, /* tp_call */
...
};
从PyInt_Type定义来看,它主要包含了int数据类型相关的方法。PyInt_Type 类型对象的初始化和PyType_Type 类型类似,PyInt_Type类型的定义也是通过全局静态变量的方式实现的,除了PyInt_Type了下,所有python内建类型都是以这种方式定义的。这些类型产生的对象都会共享这些类型对象,包括这些类型定义的方法。
在python中,怎样查看对象的类型呢?有两种方法,一种是直接type:
>>> x =
>>> type(x)
<type 'int'>
另一种是通过对象的__class__属性:
>>> x =
>>> type(x)
<type 'int'>
>>> x.__class__
<type 'int'>
现在来看看int,str,dict这些类型的类型:
<type 'int'>
>>> type(int)
<type 'type'>
>>> type(str)
<type 'type'>
>>> type(dict)
<type 'type'>
>>> type(type)
<type 'type'>
从这个输出来看,int,str,dict这些类型的类型都是type,这也印证了前面说的,所有类型都是通过元类type生成的。
读python源码--对象模型的更多相关文章
- Python源码读后小结
Python 笔记 前言(还是叫杂记吧) 在python中一切皆对象, python中的对象体系大致包含了"类型对象", "Mapping对象(dict)", ...
- Python源码剖析|百度网盘免费下载|Python新手入门|Python新手学习资料
百度网盘免费下载:Python源码剖析|新手免费领取下载 提取码:g78z 目录 · · · · · · 第0章 Python源码剖析——编译Python0.1 Python总体架构0.2 Pyth ...
- Python源码剖析——02虚拟机
<Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...
- 【读fastclick源码有感】彻底解决tap“点透”,提升移动端点击响应速度
申明!!!最后发现判断有误,各位读读就好,正在研究中.....尼玛水太深了 前言 近期使用tap事件为老夫带来了这样那样的问题,其中一个问题是解决了点透还需要将原来一个个click变为tap,这样的话 ...
- 读jQuery源码 - Deferred
Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...
- VS2013编译python源码
系统:win10 手头有个python模块,是用C写的,想编译安装就需要让python调用C编译器.直接编译发现使用的是vc9编译,不支持C99标准(两个槽点:为啥VS2008都还不支持C99?手头这 ...
- 三种排序算法python源码——冒泡排序、插入排序、选择排序
最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...
- 《python源码剖析》笔记一——python编译
1.python的架构: 2.python源码的组织结构: 3.windows环境下编译python:
- 转换器5:参考Python源码,实现Php代码转Ast并直接运行
前两个周末写了<手写PHP转Python编译器>的词法,语法分析部分,上个周末卡文了. 访问器部分写了两次都不满意,没办法,只好停下来,参考一下Python的实现.我实现的部分正好和Pyt ...
随机推荐
- 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)
关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- ExtJS 4.2 业务开发(二)数据展示和查询
本篇开始模拟一个船舶管理系统,提供查询.添加.修改船舶的功能,这里介绍其中的数据展示和查询功能. 目录 1. 数据展示 2. 数据查询 3. 在线演示 1. 数据展示 在这里我们将模拟一个船舶管理系统 ...
- PowerDesigner-VBSrcipt-自动设置主键,外键名等(SQL Server)
在PowerDesigner中的设计SQL Server 数据表时,要求通过vbScript脚本实现下面的功能: 主键:pk_TableName 外键:fk_TableName_ForeignKeyC ...
- junit4进行单元测试
一.前言 提供服务的时候,为了保证服务的正确性,有时候需要编写测试类验证其正确性和可用性.以前的做法都是自己简单写一个控制层,然后在控制层里调用服务并测试,这样做虽然能够达到测试的目的,但是太不专业了 ...
- jQuery2.x源码解析(缓存篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...
- [译]处理文本数据(scikit-learn 教程3)
原文网址:http://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html 翻译:Tacey Won ...
- Maven 整合FreeMarker使用
pom.xml <!-- freemarker jar --> <dependency> <groupId>org.freemarker</groupId&g ...
- Flexible 弹性盒子模型之CSS flex-basis 属性
实例 设置第二个弹性盒元素的初始长度为 80 像素: div:nth-of-type(2){flex-basis:80px;} 效果预览 浏览器支持 表格中的数字表示支持该属性的第一个浏览器的版本 ...
- SAP CRM 树视图(TREE VIEW)
树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...