《Python高階程式設計》(五)元類
元類
定義
物件例項化原理:物件例項化過程中會呼叫__new__和__init__方法建立新物件;作為物件的類本身也是另一種類的例項,用於建立類。
元類:負責生成其他類的類就是元類(Metaclass)
類與物件
類:相當於一個模板,具有建立物件的能力
元類:在python中,一切皆物件,p1,p2,p3…都是物件。負責生成其他類的類就是元類(Metaclass)
python中,一切皆物件,包括函式和類。
Person類也是物件,那麼它由什麼類建立的呢?
通過type函式我們就知道這個物件p1是由哪個類創建出來的:
>>> class Person: pass >>> p1 = Person() >>> p1 <__main__.Person object at 0x022EB790> >>> type(p1) #檢視p1是由哪個類建立的(Person) <class '__main__.Person'> >>> type(Person) #檢視Persion類是由哪個類建立的(type) <class 'type'> >>> type(type) <class 'type'>
總結:
- type是Python的內建類,該類是其他類物件的預設類。它是建立其他類的預設元類
- 可以使用Type而非使用Python關鍵字Class建立類。
- type建構函式接受3個引數:
- name:類的名稱
- bases:該類的基類的元組
- attrs:類中所以屬性的字典
- type是Python中的主要元類。是其他元類的基類,也是元類層級的最高階
使用type建立類
實質:其實在python中,我們使用class建立類,當你使用class關鍵字時,Python直譯器自動建立這個物件。而底層其實使用的是type函式(type函式也可以檢視例項所屬型別)來建立類的。所以我們可以直接使用type()函式來手動實現動態建立類
使用Type建立類:
def init(self, name):
self.name = name
def eat(self):
pass
def go_to_vet(self):
print "go_to_vet"
Animal = type('Animal', (object,), {
'__doc__': 'A class representing an arbitrary animal.',
'__init__': init,
'eat': eat,
'go_to_vet': go_to_vet,
})
a = Animal('abc')
print a.go_to_vet()
執行結果:
go_to_vet
None
解析:第二個引數是包含一個成員的元組:{object,}
表示:Animal類繼承於object
使用type建立繼承類:(繼承於Animal而不是object)
def meow(self):
return None
def purr(self):
print "---purr---"
return None
Cat = type('Cat', (Animal,), {
'meow':meow,
'purr':purr,
})
c = Cat('cat')
print c.purr()
檢視該物件是由什麼類建立的可以使用type:
print type(c)
print type(int):type類是基類,位於鏈的頂端,因此type(type)返回其自身
print type(5)
<class '__main__.Cat'>
<type 'type'>
<type 'int'>
object是所有類的基類,是類繼承鏈中的最高階
type也是元類層級的最高階
編寫元類
- 只需要宣告一個繼承自type的類(使用class關鍵字)
- 類只是物件,元類也只是類。元類的行為繼承自type;因此任何type的子類都可以作為元類
class Meta(type):
def __(cls, name, bases, attrs):
return super(Meta, cls).____new____(cls, name, bases, attrs)
C = Meta('C', (object,), {})
print type(C) #<class '__main__.Meta'>,即:該類是Meta的例項而不是type的例項
#元類繼承
class D(C):
pass
print type(D) #<class '__main__.Meta'>
- 可以看出,C的子類D也是Meta例項,而不是type的直接例項
- 大多數情況下類只有一個元類。即使在多繼承的情況下,如果一個類的多個子類有不同的元類,python直譯器會檢查衝突。
如果兩個元類的一個並不是另一個的直接子類,python直譯器會拒絕嘗試執行。(報出異常)
type建立類和class建立類的比較
摘自:https://blog.csdn.net/qq_26442553/article/details/82459234
- 使用type建立帶屬性和方法的類
class Person(object):
def __init__(self,name):
self.name = name
def p(self):
print("這是Person的方法")
class Animal(object):
def run(self):
print("animal can run ")
#定義一個擁有繼承的類,繼承的效果和性質和class一樣。
Worker = type("Worker",(Person,Animal),{"job":"程式設計師"})
w1 = Worker("tom")
w1.p()
w1.run()
print(type(w1),type(Worker))
'''
這是Person的方法
animal can run
<class '__main__.Worker'> <class 'type'>
<class '__main__.Person'>
總結:
- 通過type新增的屬性是類屬性,並不是例項屬性
通過type可以給類新增普通方法,靜態方法,類方法,效果跟class一樣
- type建立類的效果,包括繼承等的使用性質和class建立的類一樣。本質class建立類的本質就是用type建立。所以可以說python中所有類都是type建立的。
- type定義帶繼承,屬性和方法的類
對元類理解
元類就是類的類,python中函式type實際上是一個元類。type就是Python在背後用來建立所有類的元類。Python中所有的東西——都是物件。這包括整數、字串、函式以及類。它們全部都是物件,而且它們都是從一個類建立而來,這個類就是type。type就是Python的內建元類,當然了,也可以建立自己的元類。
使用元類
- python3中:通過呼叫Meta建立類C
class C(metaclass=Meta):
pass
- python3中,將_metaclass_屬性賦給類:
class C(object):
__metaclass__ = Meta
何時使用元類
- 大多數程式碼使用傳統的類與物件的結構都沒有問題,並不真的需要使用元類
- 說明性類宣告,例如Django模型
- 類驗證
- 非繼承屬性
用的較少,以後再補充。