python定义一个整数_深入 Python (5) 创建整数对象

A glance针对小整数的优化;

小整数区间;

ob_type 和全局整数类型对象 PyLong_Type

Start

整数对象是 Python 中最常用的对象,如果每用到一个整数对象就要进行一次对象的创建、销毁,那成本就太高了,Python 在底层对不同的整数区别对待,以提高效率。

small int

对于一些足够小的整数,Python 会预先将他们创建好,并且常驻在解释器内存的 small_ints[] 数组中,这样小整数就不需要频繁创建对象,直接引用这些全局对象就可以了。

在 Objects/longobject.c 中定义了 LongObject 的主要函数,其中 get_small_int 用于从全局解释器中获取这些小整数对象。

static PyObject *

get_small_int(sdigit ival)

{

assert(IS_SMALL_INT(ival));

PyInterpreterState *interp = _PyInterpreterState_GET();

PyObject *v = (PyObject*)interp->small_ints[ival + NSMALLNEGINTS];

Py_INCREF(v);

return v;

}

首先通过 _PyInterpreterState_GET 获取解释器,然后访问其中的小整数数组。哪些数字属于小整数呢?

#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)

由这个宏可知,当一个整数在 -NSMALLNEGINTS 和 NSMALLPOSINTS 之间时,就是小整数,它们最终的定义在 Include/internal/pycore_interp.h 中:

#define _PY_NSMALLPOSINTS 257

#define _PY_NSMALLNEGINTS 5

所以在 -5 ~ 257 之间的整数会按照小整数处理,直接引用全局对象,而非创建新对象。

创建 LongObject

在 Object/longobject.c 中实现了多种源数据创建 LongObject,最终调用的是下面的函数:

PyLongObject *

_PyLong_New(Py_ssize_t size)

{

PyLongObject *result;

/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +

sizeof(digit)*size. Previous incarnations of this code used

sizeof(PyVarObject) instead of the offsetof, but this risks being

incorrect in the presence of padding between the PyVarObject header

and the digits. */

if (size > (Py_ssize_t)MAX_LONG_DIGITS) {

PyErr_SetString(PyExc_OverflowError,

"too many digits in integer");

return NULL;

}

result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +

size*sizeof(digit));

if (!result) {

PyErr_NoMemory();

return NULL;

}

_PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size);

return result;

}

函数非常简单,计算内存大小,申请内存,最后进行初始化。其中最重要的一步是 _PyObject_InitVar((PyVarObject)result, &PyLong_Type, size);*

static inline void

_PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)

{

assert(op != NULL);

Py_SET_SIZE(op, size);

_PyObject_Init((PyObject *)op, typeobj);

}

在 _PyObject_Init 中,将当前对象与它的 type 对象关联起来,对于 LongObject 它的 ob_type 会指向 PyLong_Type,其定义在 Object/longobject.c 的第 5632 行:

PyTypeObject PyLong_Type = {

PyVarObject_HEAD_INIT(&PyType_Type, 0)

"int", /* tp_name */

offsetof(PyLongObject, ob_digit), /* tp_basicsize */

sizeof(digit), /* tp_itemsize */

/*

************* 忽略了一些代码 ************

*/

0, /* tp_alloc */

long_new, /* tp_new */

PyObject_Del, /* tp_free */

};

这是一个全局对象,可以看到第二项为 “int”,即 tp_name 类型名称,看到这里我们终于确定了 LongObject 实际上就是 Int 类型,这里可以修改 “int” 为 “Integer”,重新编译可以看到整数的类型名称从 “int” 变为 “Integer”。TypeObject 的结构稍晚再详细分析。

回顾上一节中 LongObject 的内存图,上面的代码清晰的说明了 ob_type 的指向,如果注意观察 PyLong_Type 的定义,PyLong_Type 自身也是一个 PyVarObject,PyLong_Type 不仅表示一个类型,它自己也有类型,其定义的第一行 PyVarObject_HEAD_INIT(&PyType_Type, 0) 将它的 ob_type 指向另一个类型对象 PyType_Type,说明 PyLong_Type 是一个 “表示类型对象” 的类型对象,有点绕了!如果继续追究下去,会发现 PyType_Type 也有类型,它的 ob_type 指向自己,它自己也是一个 “表示类型对象” 的类型对象。下面补全 LongObject 的图示:

关注我的公众号 江川Go,了解程序员的烧脑日常,还有开源 Python 教程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值