Python原始碼剖析----第二章
第二章 Python的整數物件
2.1 基本概念
在Python中,整數物件是不可變物件,即建立一個PyIntObject物件之後,就再也不能改變該物件所維護的那個真實的整數值了。但在實際Python的應用程式中,整數的使用太過廣泛,為避免頻繁建立,Python為整數物件使用了一個巧妙的緩衝池機制。事實上,幾乎python中所有的內建物件,都會有自己特有的物件池機制。
[intobject.h]
typedef struct{
PyObject_HEAD #物件頭結構
long ob_ival; #整數物件的值
} PyIntObject;
從定義中看出,Python中的整數物件PyIntObject實際上是對C中原生型別long的一個簡單包裝,而與整數物件PyIntObject相關的元資訊實際上都儲存在與其對應的型別物件PyInt_Type中:[intobject.c] PyTypeObject PyInt_Type= { PyObject_HEAD_INIT(&PyType_Type) 0, "int", sizeof(PyIntObject), 0, (destructor)int_dealloc, /*tp_dealloc, 整數物件的析構操作*/ (printfunc)int_print, /*tp_print, 列印PyIntObject物件 */ 0, 0, (cmpfunc)int_compare, /* tp_compare, 比較操作*/ (reprfunc)int_repr, &int_as_number, /*tp_as_number, 數值操作集合, PyNumberMethods中包含39個函式指標對應39中可選操作 */ 0, 0, (hashfunc)int_hash,/*tp_hash, 獲得Hash值*/ 0, (reprfunc)int_repr,/*tp_str,轉化成PyStringObject物件*/ PyObject_GenericGetAttr, 0, 0, int_doc, 0, 0, 0, 0, 0, 0, int_methods, /*tp_methods, 成員函式集合 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, int_new, (freefunc)int_free,/*tp_free, PyIntObject物件的釋放操作*/ );
2.2 Python中整數物件的系統結構
在實際的程式設計中,小數值的整數會被非常頻繁地使用,如果在系統堆上頻繁申請並釋放空間,不僅降低執行效率,而且會造成大量記憶體碎片,嚴重影響Python的整體效能,因此Python中,對小整數物件使用了物件池計數,通過巨集 [NSMALLEGINTS, NSMALLPOSINTS) 來確定小整數物件的定義區間,這些整數由Python直接將其對應的整數物件快取在記憶體中,並將指標存放在small_ints中。這個物件池的建立及初始化的過程在Python初始化的階段。
而對於大整數,由於空間限制,Python不可能將其完全快取,而是以PyIntBlock結構為基礎,通過兩個單向列表(PyIntBlock block_list, PyIntObject *free_list)來維護一塊記憶體空間由這些大整數輪流使用。
typedef struct _intblock{
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
}PyIntBlock;
static PyIntBlock *block_list = NULL;
Static PyIntObject *free_list = NULL;
通過PyInt_FromLong可以考察到Python中一個整數物件PyIntObject的建立
PyInt_FromLong會首先判斷小整數機制是否被啟用,如果確認小整數物件池被啟用且傳入的值屬於小整數範圍,則直接返回在池中對應的物件,否則,則轉向由block_list維護的通用物件池,從block中尋找一塊可用於儲存新的PyIntObject物件的記憶體, 如當前所有PyIntBlock中已經沒有空閒記憶體塊(freelist為空)時, Python將重新申請新的PyIntBlock並將其放入block_list, 而指標 *block_list會指向最新生成的block, 當Python需要銷燬某block中的一個整數物件時,會將該物件的使用計數置零,但其所佔用的記憶體並不會被歸還給系統,而是繼續有Python保留,並將其鏈入到free_list所維護的自由記憶體連結串列。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 *)Py_TYPE(v); PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; return (PyObject *) v; }
需要注意的是,通用物件池的大小並不是固定的,當一個整數物件的引用計數變為0時, 就會被Python回收,但是在int_dealloc中,僅僅是將該整數物件的記憶體重新加入到自由記憶體連結串列中,而不會將記憶體交回到系統堆。因此一旦系統堆中的某塊記憶體被Python申請用於整數物件,那麼這塊記憶體在Python結束前,永遠不會被釋放。因此從Python中對通用整數物件池的共享機制可以看出,Python用於實現物件池的記憶體與歷史上建立的整數物件的個數無關,而是與同一時刻共存的整數物件個數的最大值有關。
相關推薦
Python原始碼剖析----第二章
第二章 Python的整數物件 2.1 基本概念 在Python中,整數物件是不可變物件,即建立一個PyIntObject物件之後,就再也不能改變該物件所維護的那個真實的整數值了。但在實際Python的應用程式中,整數的使用太過廣泛,為避免頻繁建立,Python為整數物件
Python原始碼剖析----第一章
第一章 1.1 Python的內建物件 在python中,物件就是為C中的結構體在堆上申請的一塊記憶體,一般不能被靜態初始化 但是,型別物件是唯一的例外,python中所有的內建的型別物件都是被靜態初始化的。 Python中的內建物件的頭結構都是對Pyobject結構的擴充
Python學習系列-----第二章 操作符與表達式
2.4 學習 -- alt ges 操作符 bsp nbsp images 2.1 數學運算和賦值的簡便方法 例如: 2.2 優先級 在python中運算符有優先級之分,高優先級的運算符先執行,低優先級的運算符後執行。下面是運算符優先級:(
路飛學城——python開發集訓——第二章
決定 索引 ted 方法 插入 move 順序 其他 XP 一: 知識點總結 二進制轉換這些知識之前都有學過,暫且不記錄了。python2編碼用的是ASCII碼,python3用的則是utf-8,二者不兼容。 重點是python 的數據集,這個之前記錄過,就直接復制過來了
路飛學城——python開發集訓——第二章(2)練習題
創建 用戶 oldboy second python pda 全部 input 列表 一: 本節學習心得與體會 體會到了編程就得,多練習,列表字典集合這些知識雖然簡單,但練習題做起來還是有點磕磕絆絆的。 加深了幾個重要的知識點的使用,譬如,在索引裏用索引names
路飛學城-python開發集訓-第二章
values 增刪 val 拷貝 rom 保持 列表 利用 學習python 1.通過昨天聽必勝老師的講題客和alex老師的心靈雞湯,對個人發展和對學習的規劃有了一個清楚的認識,以後利用休息的時間多學習python,爭取實現自己的理想!2.知識點總結: 第二章學習了基本數據
Python學習(第二章)
img 開始 png 變量命名 spa cccccc otto pad 基本 一、 變量 1. type(變量名) 可以查看該變量的類型 2. 關於字符串的兩個運算符 + 與 * ,分別執行 拼接 和 重復 操作 3. 格式化輸出 %s 字符串 %d 整型 (%0
QCad原始碼分析 第二章
QCad中通過c++程式碼與js程式碼結合的方式開發,C++用於功能的開發,js用於邏輯的處理,啟用通過RScriptHandler類將c++類匯出為指令碼可呼叫的介面。 指令碼相關的類的關係如下圖:
Python入門筆記—第二章(分支迴圈 if,for,while)
第二章:分支迴圈 1.三大結構 順序(語句一條一條執行下去,則為順序,此處略過) 分支 迴圈 注:Python中沒有switch-case語句 2.分支—if 2.1 if age = 19 if age > 19:
我要翻譯《Think Python》- 004 第二章 變數, 表示式和語句
PDF原始檔地址 : http://www.greenteapress.com/thinkpython/thinkpython.pdf [自述:這一章內容不多,但是由於時間關係,翻譯完成這一章也花了我一週的時間,跟我預想的進度相比已經落後了,得加油了,要不然翻譯完整本書就要到猴年馬月了。目前離翻譯完成
Python核心程式設計 第二章--Network Programming
2.1 Introduction In this Section, we will take a brief look at network programming using sockets. But before we delve into that, w
Python 原始碼剖析(一)【python物件】
處於研究python記憶體釋放問題,在閱讀部分python原始碼,順便記錄下所得。 (基於《python原始碼剖析》(v2.4.1)與 python原始碼(v2.7.6)) 先列下總結: python 中一切皆為物件,所以會先講明白pyth
Python原始碼剖析-Dict
為了刻畫某種關係,現代的程式語言都會提供關聯式的容器。關聯式容器中的元素分別是以(鍵(key)或值(value))這樣的形式存在。例如(3,5)(3,6)就是一對對應的鍵與值。 Python中的關聯式容器是PyDictObject。Python通過PyDictObject建
Python學習系列-----第二章 操作符與表示式
2.1 數學運算和賦值的簡便方法 例如: 2.2 優先順序 在python中運算子有優先順序之分,高優先順序的運算子先執行,低優先順序的運算子後執行。下面是運算子優先順序:(同一行的運算子具有相同的優先順序) 2.3 改變優先
《Python 原始碼剖析》一些理解以及勘誤筆記(3)
以下是本人閱讀此書時理解的一些筆記,包含一些影響文義的筆誤修正,當然不一定正確,貼出來一起討論。 注:此書剖析的原始碼是2.5版本,在python.org 可以找到原始碼。紙質書閱讀,pdf 貼圖。 文章篇幅太長,故切分成3部分,這是第三部分。 p316: 初始化
Python原始碼剖析[1] —— 編譯Python
在中間的部分,可以看到Python的核心,直譯器(interpreter)。在直譯器中,箭頭的方向指示了Python執行時的資料流方向。其中Scanner對應詞法分析,將檔案輸入的Python原始碼或從命令列輸入的一行行Python程式碼切分為一個一個的token;Parser對應語法分析部分,在Scanne
【Python原始碼剖析】物件模型概述
*Python* 是一門 **面向物件** 語言,實現了一個完整的面向物件體系,簡潔而優雅。 與其他面向物件程式語言相比, *Python* 有自己獨特的一面。 這讓很多開發人員在學習 *Python* 時,多少有些無所適從。 那麼,*P
《Python編程從入門到實踐》第二章_變量和簡單數據類型
數據類型 記錄 strip() 哪些 改變 解決方法 變量名 擔心 cal 什麽是變量呢? 舉例: >>> message = "Hello,Python!" >>> print (message) Hello,Python! 這
讀書筆記--《Python基礎教程第二版》-- 第五章 條件、循環和其他語句
ja5.1 print和import的更多信息5.1.1 使用獨號輸出>>> print ‘Age:‘,42Age: 42>>> 1,2,3(1, 2, 3)>>> print 1,2,31 2 3>>> print (1,2,3)(1,
第二章 Python基礎知識
固定 list 如何獲取 思路 加減乘除 方法 oat nal 既然 第1章 第一個Pyhton程序 Pyhton的兩種執行方式:交互式與腳本文件 1.1 交互式 l 交互式模式 直接在Windows或者Linux環境下打開Python解釋器執行。 優點: