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条)