Python中的整數(shù)類型是不可變對象肠阱,為了提高python運行效率饥臂,內(nèi)部實現(xiàn)了小整數(shù)對象池(數(shù)組實現(xiàn)),和通用整數(shù)緩沖池(單鏈表實現(xiàn))茅信。小整數(shù)是可以復(fù)用的盾舌,而通用整數(shù)是即使數(shù)值相同也會創(chuàng)建兩個不同的整數(shù)對象。
1.PyIntObject
該結(jié)構(gòu)僅適用Python2版本蘸鲸,該版本下數(shù)字長度大于long型時妖谴,對象類型會轉(zhuǎn)變?yōu)镻yLongObject
PyIntObject結(jié)構(gòu):
[intobject.h]
typedef struct {
PyObject_HEAD //標(biāo)準(zhǔn)PyObject頭
long ob_ival; //實際存儲數(shù)值得變量
} PyIntObject;
整數(shù)對象的創(chuàng)建:
提供了三種創(chuàng)建方式,分類為long型創(chuàng)建或從字符串創(chuàng)建酌摇,但從字符串創(chuàng)建最終還是需要調(diào)用long型創(chuàng)建方式
PyObject *PyInt_FromLong(long ival) //從long整數(shù)創(chuàng)建
PyObject* PyInt_FromString(char *s, char **pend, int base) //從ASCII字符串創(chuàng)建
#ifdef Py_USING_UNICODE
PyObject*PyInt_FromUnicode(Py_UNICODE *s, int length, int base) //從Unicode字符串創(chuàng)建
#endif
整數(shù)對象相減:
[intobject.h]
#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)
//宏膝舅,犧牲類型安全,換取執(zhí)行效率
[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_sub(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);//此處印證了Python中整數(shù)對象是一個不可變對象
return PyLong_Type.tp_as_number->nb_subtract((PyObject *)v,
(PyObject *)w); //若溢出會將返回一個PyLongObject
}
2.小整數(shù)對象
在編程中小整數(shù)對象使用頻率很高(如循環(huán)標(biāo)記)窑多,而從上文中我們已經(jīng)得知Python中整數(shù)對象是不可變對對象仍稀,若沒有特殊的方法處理,會導(dǎo)致頻繁創(chuàng)建小整數(shù)對象埂息,嚴(yán)重影響運行效率和浪費內(nèi)存技潘。
在python內(nèi)部通過創(chuàng)建一個PyIntObject *的數(shù)組small_ints來優(yōu)化這個情況, 數(shù)組默認(rèn)范圍為[-5,257)
[intobject.c]
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257 //正數(shù)
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5 //負(fù)數(shù)
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif
3.通用整數(shù)對象
對于小整數(shù)以外的其他整數(shù)遥巴,python內(nèi)部使用多個“預(yù)先”分配的內(nèi)存塊來緩存這些整數(shù)對象,每一個內(nèi)存塊稱為一個block_list, 未使用的空間使用free_list穿起來
[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]; //PyIntObject數(shù)組享幽,用以存儲整數(shù)
};
typedef struct _intblock PyIntBlock;
static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;
4.整數(shù)對象的創(chuàng)建與刪除
整數(shù)對象的創(chuàng)建:
[intobject.c]
PyObject* PyInt_FromLong(long ival)
{
register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
//判斷小整數(shù)對象池是否激活
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { //嘗試使用小整數(shù)對象池
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return (PyObject *) v;
}
#endif
if (free_list == NULL) {//當(dāng)前block_list無空閑铲掐,需要申請新的PyIntBlock
if ((free_list = fill_free_list()) == NULL)
return NULL;
}
//使用通用整數(shù)對象池
v = free_list;
free_list = (PyIntObject *)v->ob_type;
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}
整數(shù)對象的刪除:
對整數(shù)對象進行刪除時,實際上是將該對象加入到free_list鏈表中值桩,以便整型對象的緩沖摆霉,避免頻繁的malloc操作
static void
int_dealloc(PyIntObject *v)
{
if (PyInt_CheckExact(v)) {
/*將該整型對象加入到free_list鏈表中*/
Py_TYPE(v) = (struct _typeobject *)free_list;
free_list = v;
}
else
Py_TYPE(v)->tp_free((PyObject *)v);//若為整型派生對象則僅調(diào)用指定的tp_free()
}
小整數(shù)對象池的初始化:
在Python虛擬機初始化時_PyInt_Init會被調(diào)用,創(chuàng)建小整數(shù)緩沖池
int
_PyInt_Init(void)
{
PyIntObject *v;
int ival;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* 小整數(shù)對象仍在block_list中創(chuàng)建奔坟,只是將創(chuàng)建后的對象地址存入對應(yīng)位置small_ints中 */
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
if (!free_list && (free_list = fill_free_list()) == NULL)
return 0;
v = free_list;
free_list = (PyIntObject *)Py_TYPE(v);
(void)PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
small_ints[ival + NSMALLNEGINTS] = v;//指針存入small_ints
}
#endif
return 1;
}
fill_free_list實現(xiàn):
當(dāng)free_list為NULL時創(chuàng)建新的整數(shù)對象携栋,會觸發(fā)fill_free_list操作,將malloc一個PyIntBlock蛀蜜,并將內(nèi)部的object數(shù)組中每個整數(shù)對象刻两,通過ob_type作為后繼(犧牲掉類型安全)形成單鏈表關(guān)系
[object.h]
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
[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));
if (p == NULL)
return (PyIntObject *) PyErr_NoMemory();
((PyIntBlock *)p)->next = block_list; //將新block的next鏈接到舊block_list上
block_list = (PyIntBlock *)p; //另新block為block_list頭結(jié)點
p = &((PyIntBlock *)p)->objects[0];
q = p + N_INTOBJECTS;
while (--q > p)
Py_TYPE(q) = (struct _typeobject *)(q-1); //創(chuàng)建block內(nèi)部空閑整數(shù)對象間連接關(guān)系
Py_TYPE(q) = NULL;
return p + N_INTOBJECTS - 1;
}