深入源码解析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语言技巧之三元运算符使用介绍
Mar 04 Python
Python3计算三角形的面积代码
Dec 18 Python
Python除法之传统除法、Floor除法及真除法实例详解
May 23 Python
Python 离线工作环境搭建的方法步骤
Jul 29 Python
Django框架组成结构、基本概念与文件功能分析
Jul 30 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 Python
在Pytorch中计算卷积方法的区别详解(conv2d的区别)
Jan 03 Python
Python+appium框架原生代码实现App自动化测试详解
Mar 06 Python
Pyspark获取并处理RDD数据代码实例
Mar 27 Python
Django项目创建及管理实现流程详解
Oct 13 Python
Python爬虫scrapy框架Cookie池(微博Cookie池)的使用
Jan 13 Python
忆童年!用Python实现愤怒的小鸟游戏
Jun 07 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
使用NetBeans + Xdebug调试PHP程序的方法
2011/04/12 PHP
浅析Dos下运行php.exe,出现没有找到php_mbstring.dll 错误的解决方法
2013/06/29 PHP
php自定义apk安装包实例
2014/10/20 PHP
php读取csv数据保存到数组的方法
2015/01/03 PHP
PHP的几个常用加密函数
2016/02/03 PHP
PHP对称加密函数实现数据的加密解密
2016/10/27 PHP
Zend Framework过滤器Zend_Filter用法详解
2016/12/09 PHP
老生常谈PHP位运算的用途
2017/03/12 PHP
PHP自定义错误处理的方法分析
2018/12/19 PHP
jquery 双色表格实现代码
2009/12/08 Javascript
JQuery select控件的相关操作实现代码
2012/09/14 Javascript
jQuery标签替换函数replaceWith()的使用例子
2014/08/28 Javascript
jquery实现多条件筛选特效代码分享
2015/08/28 Javascript
url中的特殊符号有什么含义(推荐)
2016/06/17 Javascript
JS获取html元素的标记名实现方法
2016/10/08 Javascript
Angular项目从新建、打包到nginx部署全过程记录
2017/12/09 Javascript
利用vue开发一个所谓的数独方法实例
2017/12/21 Javascript
微信小程序之多列表的显示和隐藏功能【附源码】
2018/08/06 Javascript
vue-cli 3.0 版本与3.0以下版本在搭建项目时的区别详解
2018/12/11 Javascript
详解puppeteer使用代理
2018/12/27 Javascript
react项目如何使用iconfont的方法步骤
2019/03/13 Javascript
js 递归json树实现根据子id查父id的方法分析
2019/11/08 Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
2020/03/14 Javascript
Vue-router中hash模式与history模式的区别详解
2020/12/15 Vue.js
[35:39]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第二场 11.22
2020/11/24 DOTA
Python删除Java源文件中全部注释的实现方法
2017/08/30 Python
python编程之requests在网络请求中添加cookies参数方法详解
2017/10/25 Python
Django 实现下载文件功能的示例
2018/03/06 Python
python实现不同数据库间数据同步功能
2021/02/25 Python
仓库规划计划书
2014/04/28 职场文书
2014基层党员批评与自我批评范文
2014/09/24 职场文书
项目备案申请报告
2015/05/15 职场文书
公司考勤管理制度
2015/08/04 职场文书
python 多态 协议 鸭子类型详解
2021/11/27 Python
分享node.js实现简单登录注册的具体代码
2022/04/26 NodeJs
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技