一篇文章告訴你什麼是 Python 元類

劉志軍發表於2018-01-28

龜叔發明了 Python,然後整合了一堆概念在這門語言裡面,比如:迭代器,裝飾器,函式,生成器,類,物件,協程等等。

這些概念對初學者似乎沒一個好懂的,不過還有比這更難的概念,它是 Python 世界中的造物主,雖然我們很少去直接使用它,但天天都在用,它就是今天的主角------元類。

今天我的任務就是徹底明白什麼是元類,看懂了別忘了給我點個贊,分享給更多人。

要搞懂元類,我們還是先從物件說起。

物件(Object)

Python 一切皆物件,這句話你一定有聽說過(現在你就聽說了),一個數字是物件,一個字串是物件,一個列表是物件,一個字典是物件,例如:

>>> i = 10
>>> s = "abc"
>>> nums = [1,2,3]
>>> dicts = {"name":"zhang"}
複製程式碼

等號右邊是物件,左邊是給這些物件取的名字,任何物件都有3個關鍵屬性:標識、值、型別。

標識

標識就和人的身份證ID一樣,每個物件有唯一ID標識,在整個生命週期中都不會變,你可以認為標識是這個物件在計算機記憶體中的地址。通過函式 id() 可以檢視物件的ID標識。

>>> id(i)
40592592
>>> id(s)
44980584
複製程式碼

物件值

物件的第二個屬性是值,值很好理解,比如 i 的值是 10,s 的值是 abc,nums 的值就是 1,2,3。

型別

物件還有一個很重要的屬性就是型別,任何物件都有屬於自己的型別,物件就是由它的型別構造出來的,比如上面的 i 的型別是 int 型別,這個物件就是由 int 構造出來的。s 型別是字串型別,nums 的型別是列表型別,dicts 的型別是字典型別,它們都是由對應的型別構建出來的。

通過 type() 可以檢視物件的型別。

>>> type(i)
<class 'int'>
>>> type(s)
<class 'str'>
>>> type(nums)
<class 'list'>
>>> type(dicts)
<class 'dict'>
複製程式碼

物件的型別也和ID標識一樣,確定好之後就不會再變化了。

類與(例項)物件

除了系統已經定義好了的整數型別,字串型別,列表等型別之外,我們還可以建立自己的型別,用關鍵字 class 來定義。例如:

>>> class Person:
		# 這裡的 self 指某個例項物件自己
...     def __init__(self, name):
			# name 是例項的屬性
...         self.name = name
		# live 是類的屬性
		live = True
複製程式碼

這裡的 Person 就是自定義類,類是一個抽象的模版,既不指張三也不是李四,現在我們可以通過呼叫這個類來構造(例項化)出一個具體的,實在的,有名字的物件出來,這個物件稱之為例項物件。

>>> p1 = Person("zhangsan")
>>> p1.name
'zhangsan'
>>>
>>> p2 = Person("lisi")
>>> p2.name
'lisi'
複製程式碼

這裡的 p1、p2 就是例項化之後的(例項)物件,這兩個物件的型別都是 Person 類,類與(例項)物件的關係就像一個車輛模具與一輛被造出來的真實車的關係一樣。

>>> p1
<__main__.Person object at 0x0195AA30>
>>> type(p1)
<class '__main__.Person'> # 這裡的__main__是模組名稱
複製程式碼

類也是物件(又叫類物件)

剛剛我們說了一切都是物件,例項(真實車)是物件,類(模具)當然也是物件,因為它也是個實實在在存在的東西,

當 Python 直譯器執行到關鍵字 class 這個指令的時候,在內部就會建立一個名為 "Person" 的類,這個類也是個物件,我們稱之為類物件(注意區別例項物件),它一樣有ID標識、有型別、有值。例如:

>>> id(Person)
26564024
>>> type(Person)
<class 'type'>
>>> Person
<class '__main__.Person'>
複製程式碼

我們注意到這個 Person 這個類物件的型別叫 “type”,也就是說 Person 類是由 type 建立出來的,現在你要記住,p1,p2 是例項物件,而 Person 是類物件。另外,這個 type 是什麼鬼?

我們來回顧一下,例項物件 p1 的型別是類物件 Person,Person 的型別 type

>>> nums = [1,2,3]
>>> type(nums)
<class 'list'>
>>> type(list)
<class 'type'>
複製程式碼

nums 的型別是 list,list 的型別也是 type,字典類(dict)的型別也是 type,所有類的型別都是 type,也就是說所有的類都是由type 建立的。這個 type 就是元類,道生一,一生二,三生萬物,元類就是 Python 中的造物主。(元類自己也是物件)

一篇文章告訴你什麼是 Python 元類

現在我們都知道類(物件)可以使用 class 關鍵字建立,我們還知道類(物件)的型別是 type,既然知道了它的型別是 type,那麼肯定可以通過 type(元類)來建立。

用元類建立類

前面講到過,type 有一個作用是用於檢查物件的型別,其實它還有另外一個作用就是作為元類動態地建立類(物件)。

>>> Person = type("Person", (), {"live":True})
>>> Person
<class '__main__.Person'>
複製程式碼

Person 就是一個類,它等價於:

>>> class Person:
...     live = True
...
>>> Person
<class '__main__.Person'>
複製程式碼

用元類 type 建立類的語法是:

type(類名,基類元組(可以為空), 屬性字典)
複製程式碼

那麼元類到底有什麼用處呢?我們真的需要元類嗎?請關注下回講解,(留給大家多些時間消化,O(∩_∩)O)

部落格: foofish.net
公眾號:Python之禪

Python之禪

相關文章