1.初识PyIntObject
本节要说的内容是“整数”,我们来看看这个PyInt_Type变量,这个变量里面大量的元信息是我们要关注的。它描述了一个整数对象。
[intobject.c]
PyTypeObject PyInt_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"int",
sizeof(PyIntObject), //对象占用内存大小
0,
(destructor)int_dealloc, /* tp_dealloc */ //对象析构
(printfunc)int_print, /* tp_print */ //打印PyIntObject对象
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */ //比较操作
(reprfunc)int_to_decimal_string, /* tp_repr */
&int_as_number, /* tp_as_number */ //一个函数域,描述作为一个number该有的行为
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)int_hash, /* tp_hash */ //获得HASH值
0, /* tp_call */
(reprfunc)int_to_decimal_string, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS, /* 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 */
int_getset, /* 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 */
};
各个函数的实现都在intobject.c中,可自行查看。
如:加法代码:
[intobject.h]
#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);
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)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);
}
2.PyIntObject的创建和维护
对象创建三种途径:
[intobject.h]
PyAPI_FUNC(PyObject *) PyInt_FromLong(long);
PyAPI_FUNC(PyObject *) PyInt_FromSize_t(size_t); //实际上调用的是PyInt_FromFloat
PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t);//实际上调用的是PyInt_FromFloat
我们主要讨论:PyInt_FromLong
------------------------------------割,以下讨论整数的存储形式,及方案------------------------------------
小整数对象使用对象池技术:Python直接将这些整数对应的PyIntObject缓存在内存中,其指针放在small_ints中
[intobject.c]
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* References to small integers are saved in this array so that they
can be shared.
The integers that are saved are those in the range
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif
大整数对象Python运行环境将提供一块内存空间,这些内存空间由这些大整数轮流使用。
[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;
通用整数对象池的创建:
[intobject.c]
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));//申请一块block的内存
if (p == NULL)
return (PyIntObject *) PyErr_NoMemory();
((PyIntBlock *)p)->next = block_list;//连接到已有的block_list中,大家非常熟悉的头接法
block_list = (PyIntBlock *)p; //重新把block_list置为头部
/* 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)
Py_TYPE(q) = (struct _typeobject *)(q-1);
Py_TYPE(q) = NULL;
return p + N_INTOBJECTS - 1;
}
[ctypes.h]
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
效果如图:
通用整数对象池的使用:
[intobject.c]
static void
int_dealloc(PyIntObject *v)
{
if (PyInt_CheckExact(v)) {
Py_TYPE(v) = (struct _typeobject *)free_list;
free_list = v;
}
else
Py_TYPE(v)->tp_free((PyObject *)v);
}
小整数对象池的创建:
[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;
/* PyObject_New is inlined */
v = free_list;
free_list = (PyIntObject *)Py_TYPE(v);
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
small_ints[ival + NSMALLNEGINTS] = v;
}
#endif
return 1;
}
创建后效果如图:事实上,小整数对象也是生存在block_list所维护的内存上
------------------------------------割,以上讨论整数的存储形式,及方案------------------------------------
现在存储有了,让我们来看看PyInt_FromLong,具体如何创建一个PyIntObject
[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);
#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);
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}