Python 物件底層實現分析

2021-09-05 11:09:58 字數 2738 閱讀 8476

pyobject物件是一切python物件共有的部分,包含以下內容:

typedef struct _object pyobject;

pyobject是所有物件共有的頭部,所以可以通過pyobject *來引用任意乙個物件, 類似於c++的繼承。

python中除了有物件可分為兩種:定長物件(int, float ...),不定長物件(字串等);

那麼python中除了pyobject外還有乙個專門用於表示變長物件的結構體 --- pyvarobject

typedef struct pyvarobject;

用於建立型別物件

比如,整數2這個物件是由pyintobject建立的,但是int這個型別(也是個物件)是由誰建立的呢?答案就是 pytypeobject

typedef struct _typeobject pytypeobject;

每個型別都有相應的型別物件。型別物件相當於乙個中轉站,比如輸出乙個物件的值

先獲取了ob_type也就是型別物件,然後呼叫相應的tp_print(不同型別資料他們的tp_print域是不一樣的)。這樣在操作乙個物件時,不需要先把這個物件轉化為相應的物件,而僅用pyobject這一塊區域(包括型別物件)就可以了,因為該物件的操作定義在型別物件中,比如現在我們只知道乙個pyobject *a, 要輸出a的值,只需要a->ob_type->tp_print(...), 而不是要先知道a的型別(整型,字串), 轉換完(pyintobject*)a, 然後再取出值轉換完(pyintobject*)a->val;

這樣的好處就是在各函式間傳遞時,我們可以只用pyobject*這種泛型指標即可完成對該物件的操作。

上面說了型別也是乙個物件,但怎麼知道這個物件是乙個型別物件呢?---pytype_type

也就是說對於普通物件,通過其對應的型別物件來確定其型別,

通過pytype_type來確定乙個物件是否是型別物件。

// pytype_type也是由pytypeobject建立的

pytypeobject pytype_type = pyintobject;

字串物件, 定義如下

typedef struct pystringobject;

intern機制:可以節省記憶體空間及提高虛擬機器執行的效率。

比如:a="python"    b="python", 那麼不採取任何措施的話,內部就要維護兩份相同的字串物件了,如果是一百個"python"呢, 那豈不是要100個相同的物件?

為了處理這種情況,python提供了intern機制,比如對於上面b採用了inter機制後,那麼建立b的時候,會先在intered這個字典中查詢是否已經存在也經過inter機制處理的相同字串,如果找到了那麼就銷毀b指向的字串物件,轉而讓b指向查詢出的相同內容的字串物件(a建立的"python"物件),這時可以看到記憶體中只有乙個"python"字串物件,ab都指向它,引用計數為2.

上面就是intern操作的**,interned是乙個字典,用來存放已經經過intern操作的字串。

注意上面在進行intern處理之前a指向的"python",與b指向的"python"物件是不同的。

pydict_getitem(intered, s);  查詢interned字典中是否存在,如果存在,那麼把t的引用計數加一,*p的引用計數減一(這裡的t就相當於上面a指向的"python"物件,*p就是b指向的這個臨時的"python"物件),相當於把這個臨時物件「銷毀「了(當然只是引用計數減一變為0了)。如果沒找到,就到下面的pydict_setitem(), 把新建立的這個物件(b指向的"python"物件)新增到interned中。

python的列表有乙個很大的好處就是可以把任意型別的資料放進去,是怎麼實現的呢?其實原因就在文章的開頭。

python中所有的物件都可以用pyobject*來指向,pyintobject, pystringobject, 包括這裡的pylistobject都可以用pyobject*型別的指標來指向,因為他們的頭部都是一樣的pyobject, 其實list中並不是直接存放各型別的指標,而是存放的pyobject*指標。下面來看一下定義:

pyobject_var_head: 變長物件共有頭部,不解釋了。

allcated: 申請的總記憶體大小(可能有申請了但沒使用的)

ob_item: 這裡就是上面說的存放pyobject指標的地方, 不太習慣的話,換一種形式pyobject **ob_item換成pyobject* ob_item, 這樣就很明顯了,ob_item這個陣列裡放的都是pyobject的指標,這麼說其實不是很合適,雖然是pyobject*,但實際指向的可能是pyintobject, pystringobject....

可能又有疑問了,既然都是pyobject*, 那怎麼知道指向的是整數物件還是字串物件呢,其實上面也已經解釋了(pyobject區域中有型別物件,而型別物件中存放了該種型別資料的操作)。

搜尋演算法是雜湊表,這個物件不再說了,太麻煩,這個物件對效率要求很高,因為和python虛擬機器直接相關的,比如名字空間,還有上面的interned等都是直接使用了這種資料結構。

參考:《python原始碼剖析》

如有錯漏,懇請指正。

HashMap底層實現分析

1.1 建立 mappersonmap new hashmap 在堆記憶體開闢空間。成員變數transient node table,transient代表不會被序列化,預設為null。static class node implements map.entry public final k get...

底層實現分析 一

1 記憶體分割槽 我們通常將記憶體分割槽劃分為以下幾大塊。1 棧區 2 堆區 3 全域性區 4 常量區 5 區 我們知道任何乙個程式在執行的時候實際上是執行在記憶體中的,這個記憶體也就是我們常說的主存,也叫執行記憶體,也叫ram random access memory 是可以直接與cpu交換資料的...

ArrayList底層實現和原理分析

今天是週末,沒什麼事就在家裡看了一下原始碼,我習慣使用jdk1.8,所以我的 全都是基於jdk1.8,好了下面是正文,今天來說說arraylist的底層實現和源 首先,集合arraylist是list的實現類,list還有兩個實現類linkedlist和vector。先說說這幾個實現類的區別吧 1....