在Python的學習中我們肯定會聽到一句話:「python中一切皆對象」。
如果再接着學習下去的話,我們就會接觸到Python中的type, object, class等概念。網上也有不少文章闡述了這三者之間的關系,但是在看了大部分文章之後我還是似懂非懂,感覺就像有什麼東西卡在了喉嚨一直咽下不去一樣。
于是為了能讓自己晚上順利吃上飯,我立馬對着搜索引擎就是一頓操作,終于趕在外賣小哥打響我電話之前,咽下了這幾個如鲠在喉的概念,舒服!
趁着外賣小哥上樓這會,分享下我學習研究後的理解吧。
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__的形式來查看。
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中對象潛藏着一些秘密了。嘿嘿嘿~
先看看下面樸而不素的代碼:
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'>,)
通過上面的很簡單的代碼,運用一眼洞穿法,我們可以根據每個打印語句的結果得到一些簡單的觀察結論:
看完上面的這些觀察結論,相信有一部分童鞋已經兩眼發懵了,什麼類A是一個類也是一個對象,object類的類型是type,而type類的父類又是object…blablabla
诶,莫方莫方,俗話說無圖言*,這裡先來一張圖簡單表示一下這幾者的關系,舒緩一下情緒:
python中type,class,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三者關系:
寫到這裡,python中這三者的關系探究就差不多了,隻能說技術寫作不是一件容易的事情,前後改了不少東西還是不那麼讓自己滿意,但是已經按照自己的意思給表述出來了,希望之後能寫得更順手一些。話說外賣小哥已經在門口等了我5分鐘了,寫文章死了那麼多腦細胞,胃口一定不錯吧哈哈。
參考文章:
如果你覺得這篇内容對你有幫助,我想邀請你幫我三個小忙:
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!