From: 使用元類app
與靜態語言最大的不一樣,就是函數和類的定義,不是編譯時定義的,而是運行時動態建立的。函數
咱們說class的定義是運行時動態建立的;測試
而建立class的方法就是使用type()
函數。spa
type()
函數既能夠返回一個對象的類型,又能夠建立出新的類型。code
問題來了:type建立了一個類?如何理解。如下即是一個 「動態建立」 的過程。對象
>>> def fn(self, name='world'): # 先定義函數 ... print('Hello, %s.' % name) ... >>> Hello = type('Hello', (object,), dict(hello=fn)) # 建立Hello class
>>> h = Hello() >>> h.hello() Hello, world. >>> print(type(Hello)) <class 'type'> >>> print(type(h)) <class '__main__.Hello'>
要控制類的建立行爲,還能夠使用metaclass。blog
metaclass,直譯爲元類,簡單的解釋就是:先定義metaclass,就能夠建立類,最後建立實例。get
因此,metaclass容許你建立類或者修改類。換句話說,你能夠把「類」當作是metaclass建立出來的「實例」。編譯
metaclass是Python面向對象裏最難理解,也是最難使用的魔術代碼。模板
正常狀況下,你不會碰到須要使用metaclass的狀況。
[實驗]:經過metaclass給咱們自定義的MyList增長一個add
方法。
定義ListMetaclass
,按照默認習慣,metaclass的類名老是以Metaclass結尾,以便清楚地表示這是一個metaclass:
# metaclass是類的模板,因此必須從`type`類型派生: classListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) # 添加了add方法 return type.__new__(cls, name, bases, attrs)
有了ListMetaclass,咱們在定義類的時候還要指示使用ListMetaclass來定製類,傳入關鍵字參數metaclass
:
class MyList(list, metaclass=ListMetaclass): pass
測試了一下,MyList能夠調用add方法。
>>> L = MyList() >>> L.add(1) >> L [1]
直接在MyList
定義中寫上add()
方法不是更簡單嗎?正常狀況下,確實應該直接寫,經過metaclass修改純屬變態。
可是,總會遇到須要經過metaclass修改類定義的。ORM就是一個典型的例子。
/* implement */
End.