python 中的object與type的關系


object 和 type的關系很像雞和蛋的關系,先有object還是先有type沒法說,obejct和type是共生的關系,必須同時出現的。

在看下去之前,也要請先明白,在Python里面,所有的東西都是對象的概念。

在面向對象體系里面,存在兩種關系:
- 父子關系,即繼承關系,表現為子類繼承於父類,如『蛇』類繼承自『爬行動物』類,我們說『蛇是一種爬行動物』,英文說『snake is a kind of reptile』。在python里要查看一個類型的父類,使用它的__bases__屬性可以查看。
- 類型實例關系,表現為某個類型的實例化,例如『萌萌是一條蛇』,英文說『萌萌 is an instance of snake』。在python里要查看一個實例的類型,使用它的__class__屬性可以查看,或者使用type()函數查看。

這兩種關系使用下面這張圖簡單示意,繼承關系使用實線從子到父連接,類型實例關系使用虛線從實例到類型連接:

 

我們將使用一塊白板來描述一下Python里面對象的關系,白板划分成三列:


先來看看type和object:
>>> object
<type 'object'>
>>> type
<type 'type'>
它們都是type的一個實例,表示它們都是類型對象。

 

在Python的世界中,object是父子關系的頂端,所有的數據類型的父類都是它;type是類型實例關系的頂端,所有對象都是它的實例的。它們兩個的關系可以這樣描述:
- object是一個type,object is and instance of type。即Object是type的一個實例。

>>> object.__class__
<type 'type'>
>>> object.__bases__ # object 無父類,因為它是鏈條頂端。
()
- type是一種object, type is kind of object。即Type是object的子類。

>>> type.__bases__
(<type 'object'>,)
>>> type.__class__ # type的類型是自己
<type 'type'>

此時,白板上對象的關系如下圖:

 

我們再引入list, dict, tuple 這些內置數據類型來看看:
>>> list.__bases__
(<type 'object'>,)
>>> list.__class__
<type 'type'>
>>> dict.__bases__
(<type 'object'>,)
>>> dict.__class__
<type 'type'>
>>> tuple.__class__
<type 'type'>
>>> tuple.__bases__
(<type 'object'>,)
它們的父類都是object,類型都是type。

再實例化一個list看看:
>>> mylist = [1,2,3]
>>> mylist.__class__
<type 'list'>
>>> mylist.__bases__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__bases__'
實例化的list的類型是<type 'list'>, 而沒有了父類。

把它們加到白板上去:

白板上的虛線表示源是目標的實例,實線表示源是目標的子類。即,左邊的是右邊的類型,而上面的是下面的父親。
虛線是跨列產生關系,而實線只能在一列內產生關系。除了type和object兩者外。

 

當我們自己去定個一個類及實例化它的時候,和上面的對象們又是什么關系呢?試一下:

>>> class C(object):
... pass
...
>>> C.__class__
<type 'type'>
>>> C.__bases__
(<type 'object'>,)

實例化
>>> c = C()
>>> c.__class__
<class '__main__.C'>
>>> c.__bases__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__bases__'
這個實例化的C類對象也是沒有父類的屬性的。
再更新一下白板:

白板上的第一列,目前只有type,我們先把這列的東西叫Type。
白板上的第二列,它們既是第三列的類型,又是第一列的實例,我們把這列的對象叫TypeObject。
白板上的第三列,它們是第二列類型的實例,而沒有父類(__bases__)的,我們把它們叫Instance。

 

你以為事情就這樣完了?不。。看見type孤零零在第一列其實不是那么舒服。。我們給它整幾個玩伴看看。但要怎么整呢?要屬於第一列的,必須是type的子類,那么我們只需要繼承type來定義類就可以了:
>>> class M(type):
... pass
...
>>> M.__class__
<type 'type'>
>>> M.__bases__
(<type 'type'>,)
>>>
嗯嗯,M類的類型和父類都是type。這個時候,我們可以把它歸到第一列去。那么,要怎么樣實例化M類型呢?實例化后它應該出現在那個列?嗯嗯,好吧,剛才你一不小心創建了一個元類,MetaClass!即類的類。如果你要實例化一個元類,那還是得定義一個類:
>>> class TM(object):
... __metaclass__ = M # 這樣來指定元類。
...
...
>>> TM.__class__
<class '__main__.M'> # 這個類不再是type類型,而是M類型的。
>>> TM.__bases__
(<type 'object'>,)

好了,現在TM這個類就是出現在第二列的。

再總結一下:
第一列,元類列,type是所有元類的父親。我們可以通過繼承type來創建元類。
第二列,TypeObject列,也稱類列,object是所有類的父親,大部份我們直接使用的數據類型都存在這個列的。
第三列,實例列,實例是對象關系鏈的末端,不能再被子類化和實例化。

 

為什么要有兩個,而不是一個。

如果type和object只保留一個,那么一定是object。只有object 時,第一列將不復存在,只剩下二三列,第二列表示類型,第三列表示實例,這個和大部分靜態語言的類型架構類似,如java 。
這樣的架構將讓python 失去一種很重要的動態特性--動態創建類型。本來,類(第二列的同學)在Python里面是一個對象(typeobject),對象是可以在運行時動態修改的,所以我們能在你定義一個類之后去修改他的行為或屬性!拿掉第一列后,第二列變成了純類型,寫成怎樣的,運行時行為就怎樣。在這一點上,並不比靜態語言有優勢。
所以,以上!
 
轉載
作者:jeff kit
鏈接:https://www.zhihu.com/question/38791962/answer/78172929
來源:知乎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM