Python中整數(shù)對象的原理是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)主營烏魯木齊網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都App制作,烏魯木齊h5微信小程序搭建,烏魯木齊網(wǎng)站營銷推廣歡迎烏魯木齊等地區(qū)企業(yè)咨詢
PyIntObject
結(jié)構(gòu)體表示:typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;
PyObject_HEAD宏中定義的兩個屬性分別是:
int ob_refcnt; struct _typeobject *ob_type;
這兩個屬性是所有Python對象固有的:
ob_refcnt:對象的引用計數(shù),與Python的內(nèi)存管理機制有關(guān),它實現(xiàn)了基于引用計數(shù)的垃圾收集機制
ob_type:用于描述Python對象的類型信息。
由此看來PyIntObject就是一個對C語言中l(wèi)ong類型的數(shù)值的擴展,出于性能考慮,對于小整數(shù),Python使用小整數(shù)對象池small_ints
緩存了[-5,257)之間的整數(shù),該范圍內(nèi)的整數(shù)在Python系統(tǒng)中是共享的。
#define NSMALLPOSINTS 257 #define NSMALLNEGINTS 5 static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
超過該范圍的整數(shù)即使值相同,但對象不一定是同一個,如下所示:a與b的值都是10000,但并不是同一個對象,值都是1是,他們屬于同一個對象。
>>> a = 10000 >>> b = 10000 >>> print a is b False >>> a = 1 >>> b = 1 >>> print a is b True
對于超出了[-5, 257)之間的其他整數(shù),Python同樣提供了專門的緩沖池,供這些所謂的大整數(shù)使用,避免每次使用的時候都要不斷的malloc分配內(nèi)存帶來的效率損耗。這塊內(nèi)存空間就是PyIntBlock
。
struct _intblock { struct _intblock *next; PyIntObject objects[N_INTOBJECTS]; }; typedef struct _intblock PyIntBlock; static PyIntBlock *block_list = NULL; static PyIntObject *free_list = NULL;
這些內(nèi)存塊(blocks)由一個單向鏈表表示,表頭是block_list
,block_list
始終指向最新創(chuàng)建的PyIntBlock對象。next指針指向下一個PyIntBlock對象,objects是一個PyIntObject數(shù)組(最終會轉(zhuǎn)變成單向鏈表),它是真正用于存儲被緩存的PyIntObjet對象的內(nèi)存空間。 free_list
單向鏈表是所有block的objects中空閑的內(nèi)存。所有空閑內(nèi)存通過一個鏈表組織起來的好處就是在Python需要新的內(nèi)存來存儲新的PyIntObject對象時,能夠通過free_list
快速獲得所需的內(nèi)存。
創(chuàng)建一個整數(shù)對象時,如果它在小整數(shù)范圍內(nèi),就直接從小整數(shù)緩沖池中直接返回,如果不在該范圍內(nèi),就開辟一個大整數(shù)緩沖池內(nèi)存空間:
[intobject.c] PyObject* PyInt_FromLong(long ival) { register PyIntObject *v; #if NSMALLNEGINTS + NSMALLPOSINTS > 0 //[1] :嘗試使用小整數(shù)對象池 if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { v = small_ints[ival + NSMALLNEGINTS]; Py_INCREF(v); return (PyObject *) v; } #endif //[2] :為通用整數(shù)對象池申請新的內(nèi)存空間 if (free_list == NULL) { if ((free_list = fill_free_list()) == NULL) return NULL; } //[3] : (inline)內(nèi)聯(lián)PyObject_New的行為 v = free_list; free_list = (PyIntObject *)v->ob_type; PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; return (PyObject *) v; }
fill_free_list
就是創(chuàng)建大整數(shù)緩沖池內(nèi)存空間的邏輯,該函數(shù)返回一個free_list
鏈表,當整數(shù)對象ival創(chuàng)建成功后,free_list
表頭就指向了v->ob_type
,ob_type
不是所有Python對象中表示類型信息的字段嗎?怎么在這里作為一個連接指針呢?這是Python在性能與代碼優(yōu)雅之間取中庸之道,對名稱的濫用,放棄了對類型安全的堅持。把它理解成指向下一個PyIntObject的指針即可。
[intobject.c] static PyIntObject* fill_free_list(void) { PyIntObject *p, *q; // 申請大小為sizeof(PyIntBlock)的內(nèi)存空間,并鏈接到已有的block list中 // block list使用指向最新創(chuàng)建的PyIntBlock p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock)); ((PyIntBlock *)p)->next = block_list; block_list = (PyIntBlock *)p; //:將PyIntBlock中的PyIntObject數(shù)組——objects——轉(zhuǎn)變成單向鏈表 p = &((PyIntBlock *)p)->objects[0]; q = p + N_INTOBJECTS; while (--q > p) // ob_type指向下一個未被使用的PyIntObject。 q->ob_type = (struct _typeobject *)(q-1); q->ob_type = NULL; return p + N_INTOBJECTS - 1; }
不同的PyIntBlock里面的空閑的內(nèi)存是怎樣連接起來構(gòu)成free_list
的呢?這個秘密放在了整數(shù)對象垃圾回收的時候,在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((PyObject *)v); }
原來PyIntObject對象銷毀時,它所占用的內(nèi)存并不會釋放,而是繼續(xù)被Python使用,進而將free_list
表頭指向了這個要被銷毀的對象上。
Python中的int對象就是c語言中l(wèi)ong類型數(shù)值的擴展
小整數(shù)對象[-5, 257]在python中是共享的
整數(shù)對象都是從緩沖池中獲取的。
整數(shù)對象回收時,內(nèi)存并不會歸還給系統(tǒng),而是將其對象的obtype指向freelist,供新創(chuàng)建的整數(shù)對象使用
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。
網(wǎng)站名稱:Python中整數(shù)對象的原理是什么
網(wǎng)頁鏈接:http://muchs.cn/article48/igejep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、外貿(mào)建站、建站公司、自適應(yīng)網(wǎng)站、網(wǎng)頁設(shè)計公司、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)