Python_int_object

  • reference: Python 源码剖析
  • Python_int_object
    • PyIntObject
    • PyIntObject对象的创建和维护
  • Hack PyIntObject

1. Python 中的整数对象(定长对象)

a.PyIntObject

  • 二分类对象

    • 定长对象 or 变长对象

    • 可变对象(mutable) or 不可变对象(immutable)

  • 1.PyIntObject是不可变对象

  • 2.Python中整数访问频繁,通过整数 对象池 ,做成一个对象的缓冲池机制,使得整数对象的使用不会成为Python的瓶颈

1
2
3
4
5
6
7
/*PyIntObject定义*/

[intobject.h]
typedef struct{
PyObject_HEAD
long ob_ival;
} PyIntObject;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*PyInt_Type定义*/
PyTypeObject PyInt_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"int",
sizeof(PyIntObject),
0,
(destructor)int_dealloc, /* tp_dealloc */
(printfunc)int_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */
(reprfunc)int_repr, /* tp_repr */
&int_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)int_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)int_repr, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE, /* tp_flags */
int_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
int_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
int_new, /* tp_new */
(freefunc)int_free, /* tp_free */
};
1
2
3
4
5
6
7
/* int_compare定义 */
[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;
}
1
2
3
4
5
6
7
8
9
10
11
/* int_as_number定义 */
[intobject.c]
static PyNumberMethods int_as_number = { /* PyNumberMethods定义了39中数值操作 */
(binaryfunc)int_add, /* nb_add */
(binaryfunc)int_sub, /* nb_subtract */
....
(binaryfunc)int_div, /* nb_floor_divide */
int_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* PyIntObject的加法实现 */
[intobject.h]
//宏,牺牲类型安全,换取执行效率
//该宏也可以用函数PyInt_AsLong来代替,但会牺牲运行效率,因为该函数做了很多类型检查
#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)

[intobject.c]
#define CONVERT_TO_LONG(obj, lng)
if (PyInt_Check(obj)){
lng = PyInt_AS_LONG(obj);
}else{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

static PyObject* int_add(PyIntObject *v, PyIntObject *w){
register long a,b,x;
CONVERT_TO_LONG(v,a);
CONVERT_TO_LONG(w,b);
x = a + b;
// 检查加法结果是否溢出(位操作比较方法)
if((x^a) >= 0 || (x^b) >= 0)
return PyInt_FromLong(x);
return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *) w);
}
1
2
3
4
5
6
/* 测试加法函数 */
>>> a = 0x7fffffff
>>> type(a)
<type 'int'>
>>> type(a+a)
<type 'long'>
  • 3.PyIntObject对象的文档信息,元信息维护在int_doc域中
1
2
>>> a = 1
>>> print a.__doc__
1
2
3
4
5
6
7
8
9
10
11
[python.h]
#define PyDoc_VAR(name) static char name[]
#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str)
#ifdef WITH_DOC_STRINGS
#define PyDoc_STR(str) str
#else
#define PyDoc_STR(str) ""
#endif

[intobject.c]
PyDoc_STRVAR(int_doc,"int(x[,base])->integer........")

b.PyIntObject对象的创建和维护

  • 对象创建的3种途径
1
2
3
4
5
6
PyObject *PyInt_FromLong(long ival)
/*PyInt_FromString和PyInt_FromUnicode都是先将字符串或Py_UNICODE转换乘浮点数,再调用PyInt_FromFloat(采用了Adaptor Pattern设计模式)*/
PyObject *PyInt_FromString(char *s,char **pend,int base)
#ifdef Py_USING_UNICODE
PyObject *PyInt_FromUnicode(Py_UNICODE *s, int length, int base)
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[intobject.c]
PyObjec* PyInt_FromString(char*s, char** pend, int base){
char* end;
long x;
.......
//将字符串转换为long值
if( base == 0 && s[0] == '0'){
x = (long) PyOS_strtoul(S,&end,base);
}else{
x = PyOS_strtol(s,&end,base);
}
.......
return PyInt_FromLong(x);
}
  • 小整数对象
1
2
3
4
5
6
7
8
9
10
[intobject.c]
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
static PyIntObject* small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif
  • 大整数对象

PyIntBlock结构+单项列表

1
2
3
4
5
6
7
8
9
10
11
12
13
[intobject.c]
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */
#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */
#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE)/sizeof(PyIntObject))

struct _intblock{
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;

static PyIntBlock* block_list = NULL;
static PyIntObject* free_list = NULL;
  • 添加和删除

以PyInt_FromLong为例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[intobject.c]
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);
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*)v->ob_type;
PyObject_INIT(v,&PyInt_Type);
v->ob_ival = ival'
return (PyObject* v);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* fill_free_list */
/* 当block满了以后free_list会再次为空,所以会再次调用fill_free_list */
/* block_list始终是指向罪最新的PyIntBlock对象 */
[intobject.c]
static PyIntObject* fill_free_list(void){
PyIntObject *p, *q;
// 申请大小为sizeof(PyIntBlock)的内存空间,并链接到已有的block list中
p = (PyIntObject *)PyMem_MALLOC(sizeof(PyIntBlock));
((PyIntBlock *)p)->next = block_list;
block_list = (PyIntBlock *)p;
// 将PyIntBlock中的PyIntObject数组--objects--转变成单项链表
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;
}

PyIntBlock

不同的PyIntBlock中的objects中的空闲块是在一个PyIntObject对象被销毁的时候被链接在一起的

1
2
3
4
5
6
7
8
9
10
/* PyIntObject对象的tp_dealloc操作 */
[intobject.c]
static void int_dealloc(PyIntObject* v){
if(PyInt_CheckExact(v)){
v->ob_type = (struct _typeobject *)free_list;
free_list = v
}else{
v->ob_type->tp_free((PyIntObject*)v);
}
}

add_delete_example

  • 小整数对象池的初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[intobject.c]
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;
//内联(inline)PyObject_New的行为
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;
}

Hack PyIntObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
static int values[10];
static int refcounts[10];
static int int_print(PyIntObject *v, FILE *fp, int flags){
PyIntObject* intObjectPtr;
PyIntBlock* p = block_list;
PyIntBlock* last = NULL;
int count = 0;
int i;
while(p != NULL){
++count;
last = p;
p = p->next;
}
intObjectPtr = last->objects;
intObjectPtr += N_INTOBJECTS - 1;
printf(" address @%p\n",v );

for( i = 0; i < 10; ++i, --intObjectPtr){
values[i] = intObjectPtr->ob_ival;
refcounts[i] = intObjectPtr->ob_refcnt;
}

printf(" value : ");
for(i = 0; i < 8; ++i){
printf("%d\t", values[i] );
}
printf("\n");

printf(" refcnt :");
for( i = 0; i < 8; ++i){
printf("%d\t", refcounts[i]);
}
printf("\n");

printf(" block_list count : %d\n", count);
printf(" free_list : %p\n", free_list );

return 0;
}
Share