本文讲述python内部是如何管理 integer
对象的
在Python中的integer对象实际上一个 PyIntObject 结构,他的值是 long
类型的属性
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
为了避免每次需要一个新的整数对象时都分配一个新的整数对象,Python会预先分配一个空闲的未使用的整数对象块。
Python使用以下结构来分配整数对象,也称为PyIntObjects。 初始化此结构后,将新的整数值分配给Python脚本中的对象时,即可使用整数对象。 该结构称为“ PyIntBlock”,并定义为:
struct _intblock {
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;
当Python分配一个整数对象块时,这些对象尚未分配任何值。 我们称它们为随时可以使用的免费整数对象。 当程序中使用新的整数值时,将为下一个空闲对象分配一个值。 设置自由整数对象的值后,将不需要内存分配,因此会很快。
块内的整数对象使用其内部指针ob_type反向链接在一起。 如源代码中所述,这是对该内部指针的滥用,因此不必过多注意名称。
每个整数块都包含一个整数对象的数量,该整数对象可以容纳1K字节的块,在我的64位计算机上大约为40个PyIntObject对象。 当使用一个块内的所有整数对象时,将为新块分配新的可用整数对象列表。
单链接列表用于跟踪分配的整数块。 在内部被称为“ block_list”
特定的结构用于引用小整数并共享它们,因此访问速度很快。 它是262个指向整数对象的指针的数组。 这些整数对象在初始化期间在我们上面看到的整数对象块中分配。 小整数范围是-5到256。许多Python程序在该范围内使用整数花费大量时间,因此这是一个明智的决定。
#define NSMALLPOSINTS 257
#define NSMALLNEGINTS 5
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
表示整数-5的整数对象在小整数数组内的偏移量0处。 代表-4的整数对象的偏移量为1…
在像这样的Python脚本中定义整数时会发生什么?
>>> a=1
>>> a
1
执行第一行时,将调用函数PyInt_FromLong,其逻辑如下:
if integer value in range -5,256:
return the integer object pointed by the small integers array at the
offset (value + 5).
else:
if no free integer object available:
allocate new block of integer objects
set value of the next free integer object in the current block
of integers.
return integer object
在我们的示例中:小整数数组将整数1对象指向偏移量:1 + 5 =6。将返回指向该整数对象的指针,并且变量“ a”将指向该整数对象。
再看一个不同的例子:
>>> a=300
>>> a
300
300不在小整数数组的范围内,因此下一个自由整数对象的值设置为300。
如果查看Python 2.6源代码中的intobject.c文件,您会看到一长串函数,这些函数负责诸如加法,乘法,转换等操作。比较函数如下所示:
static int
int_compare(PyIntObject *v, PyIntObject *w)
{
register long i = v->ob_ival;
register long j = w->ob_ival;
return (i < j) ? -1 : (i > j) ? 1 : 0;
}
整数对象的值存储在其long类型的ob_ival属性中。 每个值都放在一个寄存器中以优化访问,并且在这两个寄存器之间进行比较。 如果v指向的整数对象小于w指向的整数对象,则返回-1。 相反的返回1,如果相等则返回0。
参考:
http://www.laurentluce.com/posts/python-integer-objects-implementation/