深入源码解析Python中的对象与类型


Posted in Python onDecember 11, 2015

对象
对象, 在C语言是如何实现的?

Python中对象分为两类: 定长(int等), 非定长(list/dict等)

所有对象都有一些相同的东西, 源码中定义为PyObject和PyVarObject, 两个定义都有一个共同的头部定义PyObject_HEAD(其实PyVarObject有自己的头部定义PyObject_VAR_HEAD, 但其实际上用的也是PyObject_HEAD).

源码位置: Include/object.h

PyObject_HEAD
Python 内部, 每个对象拥有相同的头部.

定义

/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD          \
  _PyObject_HEAD_EXTRA        \
  Py_ssize_t ob_refcnt;        \
  struct _typeobject *ob_type;

说明

1. _PyObject_HEAD_EXTRA
先忽略, 双向链表结构, 后面垃圾回收再说

2. Py_ssize_t ob_refcnt
Py_ssize_t在编译时确定, 整型
ob_refcnt, 引用计数, 跟Python的内存管理机制相关(基于引用计数的垃圾回收)

3. struct _typeobject *ob_type
*ob_type 指向类型对象的指针(指向_typeobject结构体)
决定了这个对象的类型!
PyObject
定义

typedef struct _object {
   PyObject_HEAD
 } PyObject;

说明

 1. 依赖关系
 PyObject -> PyObject_HEAD
结构

深入源码解析Python中的对象与类型

PyVarObject
定义

typedef struct {
  PyObject_VAR_HEAD
} PyVarObject;

#define PyObject_VAR_HEAD        \
 PyObject_HEAD            \
 Py_ssize_t ob_size; /* Number of items in variable part */

说明

 1. 依赖关系
 PyVarObject -> PyObject_VAR_HEAD -> PyObject_HEAD

 2.Py_ssize_t ob_size
 ob_size, 变长对象容纳的元素个数
结构

深入源码解析Python中的对象与类型

代码关系

深入源码解析Python中的对象与类型

几个方法
跟对象相关的方法

#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
读取引用计数

#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
获取对象类型

#define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)
读取元素个数(len)
跟引用计数相关的方法

Py_INCREF(op)  增加对象引用计数

Py_DECREF(op)  减少对象引用计数, 如果计数位0, 调用_Py_Dealloc

_Py_Dealloc(op) 调用对应类型的 tp_dealloc 方法(每种类型回收行为不一样的, 各种缓存池机制, 后面看)
其他
几个参数涉及

ob_refcnt 引用计数, 与内存管理/垃圾回收相关
ob_type   类型, 涉及Python的类型系统

类型
一个例子

>>> a = 1
>>> a
1

>>> type(a)
<type 'int'>

#等价的两个
>>> type(type(a))
<type 'type'>
>>> type(int)
<type 'type'>

#还是等价的两个
>>> type(type(type(a)))
<type 'type'>
>>> type(type(int))
<type 'type'>

我们反向推导一个int对象是怎么生成的.

1. 首先, 定义一种类型叫PyTypeObject
代码位置 Include/object.h

定义

 

typedef struct _typeobject {

 /* MARK: base, 注意, 是个变长对象*/
 PyObject_VAR_HEAD
 const char *tp_name; /* For printing, in format "<module>.<name>" */ //类型名
 Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ // 创建该类型对象时分配的内存空间大小


 // 一堆方法定义, 函数和指针
 /* Methods to implement standard operations */
 printfunc tp_print;
 hashfunc tp_hash;

 /* Method suites for standard classes */
 PyNumberMethods *tp_as_number;  // 数值对象操作
 PySequenceMethods *tp_as_sequence; // 序列对象操作
 PyMappingMethods *tp_as_mapping; // 字典对象操作

 // 一堆属性定义
 ....

} PyTypeObject;

说明

1. PyObject_VAR_HEAD
变长对象

2. const char *tp_name
tp_name, 类型名字符串数组
所有Type都是PyTypeObject的"实例": PyType_Type/PyInt_Type

2. 然后, 用PyTypeObject初始化得到一个对象PyType_Type
代码位置 Objects/typeobject.c

定义

PyTypeObject PyType_Type = {
 PyVarObject_HEAD_INIT(&PyType_Type, 0)
 "type",                   /* tp_name */
 sizeof(PyHeapTypeObject),          /* tp_basicsize */
 sizeof(PyMemberDef),            /* tp_itemsize */
 (destructor)type_dealloc,          /* tp_dealloc */

 // type对象的方法和属性初始化值
 .....

};

说明

1. tp_name
类型名, 这里是"type"

2. PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyVarObject_HEAD_INIT, 这个方法在 Include/object.h中,
等价于
        ob_refcnt = 1
        *ob_type = &PyType_Type
        ob_size = 0

即, PyType_Type的类型是其本身!
结构

第一张图, 箭头表示实例化(google doc用不是很熟找不到对应类型的箭头)

深入源码解析Python中的对象与类型

第二张图, 箭头表示指向

深入源码解析Python中的对象与类型

使用

# 1. int 的 类型 是`type`
>>> type(int)
<type 'type'>

# 2. type 的类型 还是`type`, 对应上面说明第二点
>>> type(type(int))
<type 'type'>

注意: 无论任何时候, ob_type指向的是 PyTypeObject的实例: PyType_Type/PyInt_Type...

3. 再然后, 定义具体的类型, 这里以PyInt_Type为例子
代码位置 Objects/intobject.c

定义

PyTypeObject PyInt_Type = {
 PyVarObject_HEAD_INIT(&PyType_Type, 0)
 "int",
 sizeof(PyIntObject),
 0,

 // int类型的相关方法和属性值
 ....

 (hashfunc)int_hash,             /* tp_hash */

};

说明

1. "int"
PyInt_Type的类型名是int

2.PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyInt_Type的

 

*ob_type = &PyType_Type

结构

深入源码解析Python中的对象与类型

使用

>>> type(1)
<type 'int'>

>>> type(type(1))
<type 'type'>

4. 最后, 生成一个整数对象int
代码位置 Include/intobject.h

定义

typedef struct {
  PyObject_HEAD
  long ob_ival;
} PyIntObject;

结构

深入源码解析Python中的对象与类型

Python 相关文章推荐
python启动办公软件进程(word、excel、ppt、以及wps的et、wps、wpp)
Apr 09 Python
OpenCV+Python识别车牌和字符分割的实现
Jan 31 Python
Python3 pip3 list 出现 DEPRECATION 警告的解决方法
Feb 16 Python
如何使用Python进行OCR识别图片中的文字
Apr 01 Python
Python3列表内置方法大全及示例代码小结
May 10 Python
对Python中画图时候的线类型详解
Jul 07 Python
python读取多层嵌套文件夹中的文件实例
Feb 27 Python
jupyter notebook 使用过程中python莫名崩溃的原因及解决方式
Apr 10 Python
如何在sublime编辑器中安装python
May 20 Python
Python Selenium模块安装使用教程详解
Jul 09 Python
python生成word合同的实例方法
Jan 12 Python
Jmeter调用Python脚本实现参数互相传递的实现
Jan 22 Python
Python实现各种排序算法的代码示例总结
Dec 11 #Python
Python操作MySQL数据库9个实用实例
Dec 11 #Python
使用Python编写简单的画图板程序的示例教程
Dec 08 #Python
一波神奇的Python语句、函数与方法的使用技巧总结
Dec 08 #Python
Python使用pygame模块编写俄罗斯方块游戏的代码实例
Dec 08 #Python
用Python抢过年的火车票附源码
Dec 07 #Python
Python随手笔记之标准类型内建函数
Dec 02 #Python
You might like
PHP分页显示制作详细讲解
2008/11/19 PHP
修改ThinkPHP缓存为Memcache的方法
2014/06/25 PHP
PHP中session跨子域的三种实现方法
2016/07/25 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
jquery ajax 同步异步的执行 return值不能取得的解决方案
2012/01/08 Javascript
javascript 循环调用示例介绍
2013/11/20 Javascript
jquery进行数组遍历如何跳出当前的each循环
2014/06/05 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
JavaScript中的bold()方法使用详解
2015/06/08 Javascript
Jquery代码实现图片轮播效果(一)
2015/08/12 Javascript
学习JavaScript图片预加载模块
2016/11/07 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成&quot;...&quot;)
2016/11/28 Javascript
[Bootstrap-插件使用]Jcrop+fileinput组合实现头像上传功能实例代码
2016/12/20 Javascript
NodeJS使用七牛云存储上传文件的方法
2017/07/24 NodeJs
VUE页面中加载外部HTML的示例代码
2017/09/20 Javascript
浅谈mint-ui 填坑之路
2017/11/06 Javascript
详解element-ui中el-select的默认选择项问题
2019/08/02 Javascript
JS实现网页烟花动画效果
2020/03/10 Javascript
js实现小球在页面规定的区域运动
2020/06/16 Javascript
Element InfiniteScroll无限滚动的具体使用方法
2020/07/27 Javascript
解决windows下Sublime Text 2 运行 PyQt 不显示的方法分享
2014/06/18 Python
Python中用函数作为返回值和实现闭包的教程
2015/04/27 Python
python使用smtplib模块通过gmail实现邮件发送的方法
2015/05/08 Python
python解决汉字编码问题:Unicode Decode Error
2017/01/19 Python
python list排序的两种方法及实例讲解
2017/03/20 Python
利用python为运维人员写一个监控脚本
2018/03/25 Python
python调用百度地图WEB服务API获取地点对应坐标值
2019/01/16 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
python树的同构学习笔记
2019/09/14 Python
Python无损压缩图片的示例代码
2020/08/06 Python
国家地理在线商店:Shop National Geographic
2018/06/30 全球购物
2014年大学生自我评价
2014/01/19 职场文书
企业办公室主任岗位职责
2014/02/19 职场文书
银行主办会计岗位职责
2014/08/13 职场文书
销售团队获奖感言
2014/08/14 职场文书
自主招生自荐信范文
2015/03/04 职场文书