python的对象模型_[ Python 源码剖析] 对象模型概述
Python?是一門?面向對象?語言,實現了一個完整的面向對象體系,簡潔而優雅。
與其他面向對象編程語言相比,?Python?有自己獨特的一面。 這讓很多開發人員在學習?Python?時,多少有些無所適從。 那么,Python?對象模型都有哪些特色呢?
一切皆對象
首先,在?Python?世界,?基本類型也是對象?,與通常意義的“對象”形成一個有機統一。 換句話講,?Python?不再區別對待基本類型和對象,所有基本類型內部均由對象實現。 一個整數是一個對象,一個字符串也是一個對象:
>>> a = 1
>>> b = 'abc'
其次,?Python?中的?類型也是一種對象?,稱為?類型對象?。 整數類型是一個對象,字符串類型是一個對象,程序中通過?class?關鍵字定義的類也是一個對象。
舉個例子,整數類型在?Python?內部是一個對象,稱為?類型對象?:
>>> int
通過整數類型?實例化?可以得到一個整數對象,稱為?實例對象?:
>>> int('1024')
1024
面向對象理論中的“ 類?”和“ 對象?”這兩個基本概念,在?Python?內部都是通過對象實現的,這是?Python?最大的特點。
類型、對象體系
a?是一個整數對象(?實例對象?),其類型是整數類型(?類型對象?):
>>> a = 1
>>> type(a)
>>> isinstance(a, int)
True
那么整數類型的類型又是什么呢?
>>> type(int)
可以看到,整數類型的類型還是一種類型,即?類型的類型?。 只是這個類型比較特殊,它的實例對象還是類型對象。
Python?中還有一個特殊類型?object?,所有其他類型均繼承于?object?,換句話講?object?是所有類型的基類:
>>> issubclass(int, object)
True
綜合以上關系,得到以下關系圖:
內置類型已經搞清楚了,自定義類型及對象關系又如何呢?定義一個簡單的類來實驗:
class Dog(object):
def yelp(self):
print('woof')
創建一個?Dog?實例,毫無疑問,其類型是?Dog?:
>>> dog = Dog()
>>> dog.yelp()
woof
>>> type(dog)
Dog?類的類型自然也是?type?,其基類是?object?(就算不顯式繼承也是如此):
>>> type(Dog)
>>> issubclass(Dog, object)
True
自定義子類及實例對象在圖中又處于什么位置?定義一個獵犬類進行實驗:
class Sleuth(Dog):
def hunt(self):
pass
可以看到, 獵犬對象(?sleuth?)是獵犬類(?Sleuth?)的實例,?Sleuth?的類型同樣是?type?:
>>> sleuth = Sleuth()
>>> sleuth.hunt()
>>> type(sleuth)
>>> type(Sleuth)
同時,?Sleuth?類繼承自 Dog?類,是?Dog?的子類,當然也是?object?的子類:
>>> issubclass(Sleuth, Dog)
True
>>> issubclass(Sleuth, object)
True
現在不可避免需要討論?type?以及?object?這兩個特殊的類型。
理論上,?object?是所有類型的?基類?,本質上是一種類型,因此其類型必然是?type?。 而?type?是所有類型的類型,本質上也是一種類型,因此其類型必須是它自己!
>>> type(object)
>>> type(object) is type
True
>>> type(type)
>>> type(type) is type
True
另外,由于?object?是所有類型的?基類?,理論上也是?type?的基類(?__base__?屬性):
>>> issubclass(type, object)
True
>>> type.__base__
但是?object?自身便不能有基類了。為什么呢? 對于存在繼承關系的類,成員屬性和成員方法查找需要回溯繼承鏈,不斷查找基類。 因此,繼承鏈必須有一個終點,不然就死循環了。
這就完整了!
可以看到,所有類型的基類收斂于?object?,所有類型的類型都是?type?,包括它自己! 這就是?Python?類型、對象體系全圖,設計簡潔、優雅、嚴謹。
該圖將成為后續閱讀源碼、探索?Python?對象模型的有力工具,像地圖一樣指明方向。 圖中所有實體在?Python?內部均以對象形式存在,至于對象到底長啥樣,相互關系如何描述,這些問題先按下不表,后續一起到源碼中探尋答案。
變量只是名字
先看一個例子,定義一個變量?a?,并通過?id?內建函數取出其“地址”:
>>> a = 1
>>> id(a)
4302704784
定義另一個變量?b?,以?a?賦值,并取出?b?的“地址”:
>>> b = a
>>> id(b)
4302704784
驚奇地看到,?a?和?b?這兩個變量的地址居然是相同的!這不合常理呀!
對于大多數語言(?C?語言為例),定義變量?a?即為其分配內存并存儲變量值:
變量?b?內存空間與?a?獨立,賦值時進行拷貝:
在?Python?中,一切皆對象,整數也是如此,?變量只是一個與對象關聯的名字?:
而變量賦值,只是將當前對象與另一個名字進行關聯,背后的對象是同一個:
因此,在?Python?內部,變量只是一個名字,保存指向實際對象的指針,進而與其綁定。 變量賦值只拷貝指針,并不拷貝指針背后的對象。
可變對象 與 不可變對象
定義一個整數變量:
>>> a = 1
>>> id(a)
4302704784
然后,對其自增?1?:
>>> a += 1
>>> a
2
>>> id(a)
4302704816
數值符合預期,但是對象變了!初學者一臉懵逼,這是什么鬼?
一切要從?可變對象?和?不可變對象?說起。?可變對象?在對象創建后,其值可以進行修改; 而?不可變對象?在對象創建后的整個生命周期,其值都不可修改。
在?Python?中,整數類型是不可變類型, 整數對象是不可變對象。 修改整數對象時,?Python?將以新數值創建一個新對象,變量名與新對象進行綁定; 舊對象如無其他引用,將被釋放。
每次修改整數對象都要創建新對象、回收舊對象,效率不是很低嗎? 確實是。 后續章節將從源碼角度來解答:?Python?如何通過?小整數池?等手段進行優化。
可變對象是指創建后可以修改的對象,典型的例子是?列表?(?list?):
>>> l = [1, 2]
>>> l
[1, 2]
>>> id(l)
4385900424
往列表里頭追加數據,發現列表對象還是原來那個,只不過多了一個元素了:
>>> l.append(3)
>>> l
[1, 2, 3]
>>> id(l)
4385900424
實際上,列表對象內部維護了一個?動態數組?,存儲元素對象的指針:
列表對象增減元素,需要修改該數組。例如,追加元素?3?:
定長對象 與 變長對象
Python?一個對象多大呢?相同類型對象大小是否相同呢? 想回答類似的問題,需要考察影響對象大小的因素。
標準庫?sys?模塊提供了一個查看對象大小的函數?getsizeof?:
>>> import sys
>>> sys.getsizeof(1)
28
先觀察整數對象:
>>> sys.getsizeof(1)
28
>>> sys.getsizeof(100000000000000000)
32
>>> sys.getsizeof(100000000000000000000000000000000000000000000)
44
可見整數對象的大小跟其數值有關,像這樣?大小不固定?的對象稱為?變長對象?。
我們知道,位數固定的整數能夠表示的數值范圍是有限的,可能導致?溢出?。?Python?為解決這個問題,采用類似?C++?中?大整數類?的思路實現整數對象 —— 串聯多個普通?32?位整數,以便支持更大的數值范圍。 至于需要多少個?32?位整數,則視具體數值而定,數值不大的一個足矣,避免浪費。
這樣一來,整數對象需要在頭部額外存儲一些信息,記錄對象用了多少個?32?位整數。 這就是變長對象典型的結構,先有個大概印象即可,后續講解整數對象源碼時再展開。
接著觀察字符串對象:
>>> sys.getsizeof('a')
50
>>> sys.getsizeof('abc')
52
字符串對象也是變長對象,這個行為非常好理解,畢竟字符串長度不盡相同嘛。 此外,注意到字符串對象大小比字符串本身大,因為對象同樣需要維護一些額外的信息。 至于具體需要維護哪些信息,同樣留到源碼剖析環節中詳細介紹。
那么,有啥對象是定長的呢?—— 浮點數對象?float?:
>>> sys.getsizeof(1.)
24
>>> sys.getsizeof(1000000000000000000000000000000000.)
24
浮點數背后是由一個?double?實現,就算表示很大的數,浮點數對象的大小也不變。
為啥?64?位的?double?可以表示這么大的范圍呢?答案是:犧牲了精度。
>>> int(1000000000000000000000000000000000.)
999999999999999945575230987042816
由于浮點數存儲位數是固定的,它能表示的數值范圍也是有限的,超出便會拋錨:
>>> 10. ** 1000
Traceback (most recent call last):
File "", line 1, in
OverflowError: (34, 'Result too large')
更多章節
洞悉 Python 虛擬機運行機制,探索高效程序設計之道!
到底如何才能提升我的 Python 開發水平,向更高一級的崗位邁進? 如果你有這些問題或者疑惑,請訂閱我們的專欄,章節:
附錄
更多 Python 技術文章請訪問:小菜學 Python,轉至 原文 可獲得最佳閱讀體驗。
訂閱更新,獲取更多學習資料,請關注 小菜學編程 :
總結
以上是生活随笔為你收集整理的python的对象模型_[ Python 源码剖析] 对象模型概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python excel取数 生成报告_
- 下一篇: mysql 视图慢_第03问:磁盘 IO