
bilibili视频讲解:https://space.bilibili.com/431392724
用户名:平凡的久月
Python3中用LongObject表示整型Number,Python2中用IntObject和LongObject表示整型Number。
1. PyLongObject 概述在Python中没有对象能被完全被声明为一个PyObject,但每一个指向Python的对象的指针均能够被视为一个PyObject* 指针。
1.1 Python3中一个整型数字占多少个字节?struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
typedef uint32_t digit;
#define PyObject_VAR_HEAD PyVarObject ob_base;
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size;
} PyVarObject;
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
// 如果定义了Py_TRACE_REFS的话,这个结构将可以支持双向列表,并且所有堆中的活动均在这个列表中
// 因为在 release模式 下没有定义Py_TRACE_REFS,所以可以忽略这个宏或者理解为null
#ifdef Py_TRACE_REFS
#define _PyObject_HEAD_EXTRA
struct _object *_ob_next;
struct _object *_ob_prev;
#define _PyObject_EXTRA_INIT 0, 0,
#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif
现在主要来研究Py_ssize_t,先说结论:Py_ssize_t在64位系统中是64位的int,而32位系统是_W64,所以Py_ssize_t的本质为一个8个字节的int类型。
// Include/pyport.h #ifdef HAVE_SSIZE_T typedef ssize_t Py_ssize_t; #elif SIZEOF_VOID_P == SIZEOF_SIZE_T typedef Py_intptr_t Py_ssize_t; #else # error "Python needs a typedef for Py_ssize_t in pyport.h." #endif
关于HAVE_SSIZE_T,对于HAVE_SSIZE_T的默认定义为 1 。
关于ssize_t,即我们默认下,根据平台将ssize_t的类型设置为__int64或者_W64。
// 这两项定义在 PC/pyconfig.h 中,这里非常重要!!! #ifdef MS_WIN64 typedef __int64 ssize_t; #else typedef _W64 int ssize_t; #endif #define HAVE_SSIZE_T 1
终上所述,PyLongObject可以等价为下列表达,至少为24个字节。同时·,也可以看出LongObject是一个变长对象(obsize决定)。
struct _longobject {
_PyObject_HEAD_EXTRA // release模式下为null
Py_ssize_t ob_refcnt; // 8个字节
struct _typeobject *ob_type; // 8个字节(指针与系统寻址能力有关,64位系统则为8个字节)
Py_ssize_t ob_size; // 8个字节
digit ob_digit[1]; // 以四个字节为间距增加,可以没有(ob_size=0)
};
1.2 整数对象池
整数对象的缓冲池机制
面向特定对象的缓冲池机制也是Python语言实现时的核心设计策略之一
1.3 一般对象的创建与运行对于PyLongObject,与对象相关的原信息保存在与对象对应的类型对象中,其对应PyLong_Type。
整型对象创建过程概括:实例化对象(PyLongObject) --> PyLong_Type(PyTypeObject) --> PyType_Type(PyTypeObject)
先看基本Object
可以看出,各种对象都拥有相同的对象头部,因此只需要一个PyObject *指针就可以引用任意一个对象,而不论该对象实际是一个什么对象。这也就是 PyObject是对象机制基石 的原因。
再看对象的创建过程(以整型对象为例进行一般过程概括,其实整型对象的创建稍有区别,后面会详细说明)
调用类型对象的tp_new(int(PyLongObject) --> PyLong_Type(PyTypeObject));
如果上述tp_new=null,则根据tp_base找到指定的基类;
调用基类中的tp_new(所有类都是以object类为基类的,所以总是能找到一个非空的tp_new);
访问类型对象PyLong_Type中的tp_basicsize信息,完成内存申请 *** 作(这个信息记录这一个整数对象应该占用多大内存);
调用tp_init完成初始化对象的工作。
最后看看运行时对象与类型的关系
1.4 PyLongObject对象的元信息根据源码尝试自己回答以下问题
两个整数对象如何比较大小?(longobject.c)
加法 *** 作如何实现?
// longobject.c
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
// ......
}
如何理解 long_as_number 与 PyNumberMethods的关系?
// object.h
#ifndef Py_LIMITED_API
typedef struct {
binaryfunc nb_add;
// .......
} PyNumberMethods;
// longobject.h
static PyNumberMethods long_as_number = {
(binaryfunc)long_add,
(binaryfunc)long_sub,
0,
// ......
};
如何通过加法 *** 作理解整型对象时不可变对象(immutable)?
结合返回值进行考虑
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)