在學python?type、object、class這些不瞭解一下嗎?

在Python的學習中咱們確定會聽到一句話:「python中一切皆對象」python

若是再接着學習下去的話,咱們就會接觸到Python中的type, object, class等概念。網上也有很多文章闡述了這三者之間的關係,可是在看了大部分文章以後我仍是似懂非懂,感受就像有什麼東西卡在了喉嚨一直嚥下不去同樣。web

因而爲了能讓本身晚上順利吃上飯,我立馬對着搜索引擎就是一頓操做,終於趕在外賣小哥打響我電話以前,嚥下了這幾個如鯁在喉的概念,舒服!
趁着外賣小哥上樓這會,分享下我學習研究後的理解吧。算法

python中的對象

python做爲面向對象的語言之一,符合一切基於面向對象理念的設計。在面向對象的體系中,對象存在着兩種關係。後端

繼承關係

簡單來講即子類繼承於父類,子類擁有其自身及父類的方法和屬性,同名的子類方法和屬性將會覆蓋父類的方法和屬性。
語義化的理解栗子爲:「蛇」類繼承自「爬行動物類」,因此「蛇是一種爬行動物」,英文說「snake is a kind of reptile」
在python中的繼承關係能夠簡單表示以下:數據結構

class Reptile:
    title = '爬行動物'
    def crawl(self):
        print(self.title)

class Snake(Reptile):
    def crawl_a(self):
        print(self.title)

p = Snake()
p.crawl()  # 爬行動物
p.crawl_a() # 爬行動物
print(p.title) # 爬行動物
複製代碼

上面這個栗子中,子類Snake繼承了父類Reptile的title屬性和crawl方法,使得類B的實例對象b能調用父類的a屬性和get方法。
另外,若是要查看一個類(class)的父類,可使用class_name.__bases__的形式來查看。app

Snake.__bases__ # (<class '__main__.Reptile'>,)
複製代碼

實例化關係

若是繼承關係比如父與子的關係,實例化關係則是一個從抽象到具體的過程。實例是某個類中具體的個體的表示。
語義化的理解栗子爲:「小p是一條蛇」,「蛇」是一個分類,「小p」則是這個分類中的一個具體的個體。英文說「小p is an instance of snake」學習

class Snake:
    pass

p = Snake() # p是Snake類的實例對象
複製代碼

若是想要查看一個對象是由哪一個類實例化而來,可使用type()object_name.__class__來查看。表示對象屬於什麼類型。搜索引擎

type(p) # <class '__main__.Snake'> 表示對象p是由類Snake實例化而來,p的類型是Snake
p.__class__ # <class '__main__.Snake'> 表示對象p是由類Snake實例化而來,p的類型是Snake
複製代碼

探究對象的祕密

有了以上的基礎,咱們就能夠一步一步來探究python中對象潛藏着一些祕密了。嘿嘿嘿~ spa

先看看下面樸而不素的代碼:.net

class A:
    pass

a = A()

print(A.__bases__) # (<class 'object'>,)
print(object.__bases__) # ()
print(type(a)) # <class '__main__.A'>
print(type(A)) # <class 'type'>
print(type(object)) # <class 'type'>
print(type.__bases__) # (<class 'object'>,)
複製代碼

經過上面的很簡單的代碼,運用一眼洞穿法,咱們能夠根據每一個打印語句的結果獲得一些簡單的觀察結論:

  1. 若是定義一個類時沒有指定繼承哪一個類,則默認繼承object類
  2. object類的父類爲空,說明object類位於繼承關係鏈的頂端,object類是Python中全部類的父類,能夠說object是python中的頂端類
  3. 對象a由類A實例化而來,a的類型爲A,這個比較容易理解。
  4. 根據3的觀察結果,一樣的觀察手法運用在類A上,觀察到類A是由type這個類實例化而來,類A的類型爲type,說明類A是一個類的同時也是一個對象(類A是類type的實例化對象)。這裏可能有點暈可是請先接着看下去吧。
  5. 根據3的觀察結果,一樣的觀察手法運用在頂端類object上,觀察到object這個頂端類也是由type這個類實例化而來,類object的類型也爲type,也說明object做爲一個類的同時也是一個對象。
  6. 類`type`做爲實例化類`A`和類`object`的類,其父類爲`object`

看完上面的這些觀察結論,相信有一部分童鞋已經兩眼發懵了,什麼類A是一個類也是一個對象,object類的類型是type,而type類的父類又是object…blablabla

誒,莫方莫方,俗話說無圖言*,這裏先來一張圖簡單表示一下這幾者的關係,舒緩一下情緒:

python中type,class,object三者關係圖
python中type,class,object三者關係圖

下面咱們就能夠開始看圖寫做文啦~
藍色箭頭由實例對象指向實例化它的類,紅色箭頭由子類指向父類。值得注意的是,這個圖有幾個關鍵的地方:

  • 類(如class A, class object)都是由type這個類實例化而來的,即全部類(class)對象的類型都是type
  • type這個類也是由type本身實例化而來的(圖中type處指向自身的部分),即type類的類型也爲type
  • type類的父類是object類

有了以上的鋪墊,咱們能夠知道一個最普通的實例對象鏈是這樣子的:

type --實例化--> object --衍生--> class --實例化--> a(具體對象)

這部分都是比較好理解的,但關鍵的問題是 ———— object類做爲type類的父類,怎麼會是由type類實例化出來的?還有type類竟然是由type本身實例化出來的?這都是什麼操做?

我的認爲,這兩個問題解決了才能更好地理解type、class、object三者的關係。然而要知道爲何python是這樣設計的,最好的作法即是去翻他們的源碼啦。不過在翻以前,其實已經有一些大佬對python的源碼作了解讀,經過搜索引擎認真找尋即可找到想要的答案。python的底層是C的實現,下面的源碼若是看不懂的話請別在乎,由於不妨礙理解。

(⊙o⊙)

咱們能夠看看在源碼中,type類和object類分別是什麼:
type類其實是:

#define PyVarObject_HEAD_INIT(type, size)
    1, type, size,

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    0,                                          /* tp_base */
    ...
}
複製代碼

object類其實是:

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    sizeof(PyObject),                           /* tp_basicsize */
    0,                                          /* tp_itemsize */
    0,                                          /* tp_base */
    ...
}
複製代碼

這兩個類結構體中的各項的具體含義這裏不作深究,由於不在本文研究範圍內。咱們只須要關注這兩個結構中的第一行:

PyVarObject_HEAD_INIT(&PyType_Type, 0)

它表示這個類結構的對象類型。能看出來object 類 和 type 類的對象類型都是 &PyType_Type,而 PyType_Type 正是底層表示type類的結構體!
這兩個結構體就說明了:
object類將類型(即誰實例化了這個類)設置成了type類,type類將類型設置成了本身!這實際上是python底層實現的一個小小的trick~

而後在type類的初始化過程當中,執行了以下代碼:

type->tp_base = &PyBaseObject_Type;
複製代碼

轉換成python爲

type.__base__ = (object,) 
複製代碼

表示將object類指定爲type類的父類,這不就是第二個問題的答案所在嗎?
源碼看到這裏,前面的兩個問題就已經所有解決了,咱們能夠開始全面總結一下type,class,object的關係了。

總結

type,class,object三者關係:

  • object類是全部類(class)的父類,包括type類,object類的父類爲空。
  • type類是全部類的類型,即爲全部類(class)均可由type實例化而來,包括type類本身。
    將上面的關係總結成一張圖就是:
    pyhton三者關係全
    pyhton三者關係全

後記&引用

寫到這裏,python中這三者的關係探究就差很少了,只能說技術寫做不是一件容易的事情,先後改了很多東西仍是不那麼讓本身滿意,可是已經按照本身的意思給表述出來了,但願以後能寫得更順手一些。話說外賣小哥已經在門口等了我5分鐘了,寫文章死了那麼多腦細胞,胃口必定不錯吧哈哈。


參考文章:

讀後三連⭐️

若是你以爲這篇內容對你有幫助,我想邀請你幫我三個小忙:

  1. 點贊,讓更多的人也能看到這篇內容(這對我真的很重要)
  2. 關注公衆號「py一下」,不按期分享原創知識,python/後端/業務/數據結構與算法等
  3. 也多看看其餘文章

相關文章
相關標籤/搜索