【Python】整数
2018-10-26 本文已影响10人
lndyzwdxhs
0x01 PyIntObject
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
PyIntObject
对象表示一个整数(long
类型的)。它是一个不可变对象,一旦创建了以后,值不能被改变。
整数是非常常见的对象。使用奇数指针表示整数可以节省很多空间,但是在特殊情况下需要贯穿整个代码来检查(Using odd pointers to represent integers would save much space but require extra checks for this special case throughout the code
)。
由于一个典型的python
程序需要使用很多次整数,所以就要申请和释放内存很多次,这个过程理应是非常快的。因此我们使用具有很低开销的专门的内存分配方案,而不是直接使用malloc()
:一个简单的专用空闲列表,在需要的时候申请内存填充这个列表。
block_list
是所有PyIntBlocks
对象(all PyIntBlocks
)组成的单向链表,PyIntBlocks
是之前申请的内存结构,链表通过节点的下一个成员连接(linked via their next members
)。PyIntBlocks
在系统结束(shutdown
)的时候会返回给操作系统。
free_list
是可以使用的PyIntObjects
对象(available PyIntObjects
)组成的单向链表,通过ob_type
成员的滥用来连接这个链表(linked via abuse of their ob_type members
)。
-
fill_free_list
函数解析:申请一个新的PyIntBlock
对象,存在在链表block_list
的最前头;然后将PyIntObject
类型的数组objects
从后往前使用ob_type
链接起来,组成一个链表,最后返回链表头,也就是objects
数组的最后一个元素。
static PyIntObject *
fill_free_list(void)
{
PyIntObject *p, *q;
/* Python's object allocator isn't appropriate for large blocks. */
p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));
if (p == NULL)
return (PyIntObject *) PyErr_NoMemory();
((PyIntBlock *)p)->next = block_list;
block_list = (PyIntBlock *)p;
/* Link the int objects together, from rear to front, then return
the address of the last int object in the block. */
p = &((PyIntBlock *)p)->objects[0];
q = p + N_INTOBJECTS;
while (--q > p)
q->ob_type = (struct _typeobject *)(q-1);
q->ob_type = NULL;
return p + N_INTOBJECTS - 1;
}

- 小整数初始化:
python
中创建整数对象的时候,如果属于小整数范围(-5~257
,各个系统或版本这个范围可能不同),直接使用提前缓存的对象,不用重新创建,提高效率;每创建一个python
整数对象,引用计数也会增加。
int
_PyInt_Init(void)
{
PyIntObject *v;
int ival;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
if (!free_list && (free_list = fill_free_list()) == NULL)
return 0;
/* PyObject_New is inlined */
v = free_list;
free_list = (PyIntObject *)v->ob_type;
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
small_ints[ival + NSMALLNEGINTS] = v;
}
#endif
return 1;
}
// test demon:
// test.c
#include <stdlib.h>
#include <stdio.h>
#define NSMALLNEGINTS 5
#define NSMALLPOSINTS 257
int small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
int main()
{
int ival;
for(ival=-NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++){
small_ints[ival + NSMALLNEGINTS] = ival;
}
for(int i=0; i<NSMALLNEGINTS + NSMALLPOSINTS; i++){
printf("index:%d, value:%d\n", i, small_ints[i]);
}
return 0;
}
// 执行结果:
// ./test
index:0, value:-5
index:1, value:-4
index:2, value:-3
index:3, value:-2
index:4, value:-1
index:5, value:0
index:6, value:1
index:7, value:2
index:8, value:3
index:9, value:4
index:10, value:5
index:11, value:6
index:12, value:7
......
-
PyIntObject
创建:可以从long
、unicode
、string
类型生成PyIntObject
对象,但是最后都是调用到PyObject * PyInt_FromLong(long ival)
函数。先判断数值是否在小整数范围内,如果不在范围内,就从free_list
中取一个PyIntObject
对象,然后赋上需要创建的值
PyObject *
PyInt_FromLong(long ival)
{
register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
#ifdef COUNT_ALLOCS
if (ival >= 0)
quick_int_allocs++;
else
quick_neg_int_allocs++;
#endif
return (PyObject *) v;
}
#endif
if (free_list == NULL) {
if ((free_list = fill_free_list()) == NULL)
return NULL;
}
/* Inline PyObject_New */
v = free_list;
free_list = (PyIntObject *)Py_TYPE(v);
(void)PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}
欢迎关注微信公众号(coder0x00)或扫描下方二维码关注,我们将持续搜寻程序员必备基础技能包提供给大家。