首頁 > 軟體

Python萬物皆物件理解及原始碼學習

2022-05-17 22:00:56

萬物皆物件

這篇部落格的內容主要是針對Python中萬物皆物件的理解,對Python的型別、物件體系做一個整體的梳理。

在Python中,一切皆為物件,一個整數是一個物件,一個字串也是一個物件,基本型別(如int)也是物件。Python不再區別對待基本型別和物件,所有的基本型別內部均由物件實現。

>>> a = int
>>> b = 1
>>> id(a)
140734789683952
>>> id(int)
140734789683952
>>> a
<class 'int'>
>>> id(b)
2421963817200
>>> id(1)
2421963817200
>>> b
1

1 型別物件和範例物件

Python中的型別是一種物件,稱為型別物件。整數型別、字串型別,以及我們通過class關鍵字定義的自定義型別也是一個物件。

通過類範例化可以得到一個範例化物件,稱為範例物件

2 型別、物件體系

2.1 元型別type

前面我們提到:Python中的型別是一種物件,稱為型別物件。那麼型別物件的型別又是什麼呢?

>>> type(int)
<class 'type'>
>>> int.__class__
<class 'type'>

可以看到,型別的型別是type,我們稱之為元型別,但是這個型別比較特殊,它的範例物件是型別物件。此外,Python中還有一個特殊的型別object,所有其他型別都繼承於object,即object是所有型別的基礎類別。

圖示如下:

2.2 自定義型別

除了Python的內建型別,我們自定義一個型別MyClass,同樣地,可以得到:

2.3 自定義型別子類

再定義一個型別MySubClass,該型別為MyClass的子類:

2.4 type和object的關係

在上述範例中,我們描述了不同物件、型別之間的繼承、型別關係,但是對於兩個特殊的型別type和object的關係並沒有指出,我們先來列印看一下:

>>> type(type)
<class 'type'>
>>> type(object)
<class 'type'>
>>> type.__base__
<class 'object'>
>>> object.__base__
>>> print(object.__base__)
None

可以看到:object的型別也是type,type本身的型別也是type;而type的父類別也是所有物件的父類別——object,而object本身沒有父類別。由此我們可以歸納出:

object是所有型別的基礎類別(除了它自己),本質上是一種型別,其型別是type,同時也是type的基礎類別;

type是所有型別的型別,本質上是一種型別,其型別是它自己,也是object的型別;

注:object本身不能有基礎類別,這是因為——對於存在繼承關係的類,成員屬性和成員方法查詢需要回溯繼承鏈,不斷查詢基礎類別。因此,繼承鏈必須有一個終點,不然就會死迴圈。

最後我們把type和object的關係補充進來:

3 可變物件與不可變物件

可變物件在建立之後,其值可以修改;不可變物件在建立之後,其值不可以進行修改。

以Python中的整數物件為例:整數型別是不可變型別,整數物件是不可變物件。“修改整數物件”時,Python將以新值建立一個新物件,變數名與新物件進行繫結,舊物件如果沒有其他參照,則會被釋放(通過“小整數池”進行建立回收優化,具體後續介紹,這裡先按下不表,後續會補充)。

圖示如下:

以Python中的列表物件為例:列表型別是可變型別,列表物件是可變物件。列表物件內部會維護一個動態陣列,儲存元素物件的指標,列表物件再增減物件的時候,會修改該陣列,而列表物件的“頭部”(後續會詳細介紹)會保持不變:

4 變長物件和定長物件

定長物件:物件的記憶體大小一定

邊長物件:同一型別,不同物件會有不同的大小

通過sys.getsizeof()可以檢視一個物件的大小:

>>> import sys
>>> a = 1
>>> b = 1111111111111111111111111111111111111111111111111111111111
>>> c = 1.0
>>> d = 1.00000000000000000000000000000000000000000000000000000001
>>> sys.getsizeof(a)
28
>>> sys.getsizeof(b)
52
>>> sys.getsizeof(c)
24
>>> sys.getsizeof(d)
24

整數物件是變長物件:固定位數的整數能夠表示的範圍是有限的,故整數物件會隨著自身的數值大小而改變自身記憶體大小。在Python中採用了類似C++中大整數類的思路實現整數物件,通過串聯多個普通32位元整數來支援更大的數值範圍(詳細原始碼後續介紹)。

浮點數物件是定長物件:根據機組的知識,我們用32位元表示單精度浮點數,用64位元表示雙精度浮點數,它們都是定長的。在Python中,浮點數背後是由一個double來實現的,就算表示很大的數,浮點數物件的大小也不變(這樣做的代價是犧牲了精度)。當然,浮點數也是有大小限制的,可以思考下:我們通過float()將一個很大的int轉化為float時,是否會報錯?Python底層是否做了相應的判斷呢?

5 補充

變數名:我們建立物件時會為物件分配對應的記憶體空間,那麼我們將變數名和物件繫結時,變數又是如何儲存的呢?

詳見Python原始碼學習筆記:Python作用域與名稱空間

以上就是Python萬物皆物件理解及原始碼學習的詳細內容,更多關於Python物件的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com