最近了解了一下python的metaclass,在學習的過程當中,把本身對metaclass的理解寫出來和你們分享。python
首先, metaclass 中文叫元類,這個元類怎麼來理解呢。咱們知道,在Python中,一切都是對象。咱們定義一個類,而後實例化,獲得了一個類的實例對象。咱們能夠把類理解成建立實例對象的模板。其實,這個模板,也就是類自己,也是一個對象。既然類也是對象,那麼咱們就能夠對他進行不少操做。好比,把類做爲函數的參數,建立類的引用等等。那麼建立類的模板,就是元類。函數
在Python中,咱們很早就接觸了一個函數 type,用來返回對象的類型。好比學習
In [1]: print(type(1)) <type 'int'> In [2]: print(type("1")) <type 'str'> In [3]: def foo():pass In [4]: print (type(foo)) <type 'function'> In [5]: class Foo():pass In [6]: print(type(Foo())) <type 'instance'> In [7]: print(type(Foo)) <type 'classobj'>
其實 type函數還有另一個用處,那就是用來建立類,用法就是spa
type(classname,(superclassname,),{attrs}),咱們來看一下:code
MyClass = type("MyClass",(),{})
其實等效於對象
class MyClass(): pass
咱們說過,metaclass是建立類的類,因此,type就是一個metaclass。咱們來驗證一下blog
In [23]: age.__class__ Out[23]: int In [24]: name.__class__ Out[24]: str In [25]: MyClass().__class__ Out[25]: __main__.MyClass In [26]: MyClass().__class__.__class__ Out[26]: type In [29]: age.__class__.__class__ Out[29]: type In [30]: name.__class__.__class__ Out[30]: type
type是內置的metaclass,咱們也能夠本身定義本身的元類。在定義類的時候,定義 __metaclass__屬性,這種狀況下,Python就會使用metaclass 來建立類。具體模式以下:it
在建立類時,Python會尋找有沒有定義__metaclass__,若是有,就用定義好的metaclass來建立類。io
若是在當前類找不到 __metaclass__,Python會在當前模塊下尋找__metaclass__function
若是仍是找不到,Python會尋找當前類第一個父類的__metaclass__,直到最後的內建函數type()
那麼__metaclass__定義究竟是什麼呢?
是任何可以建立類的,好比type或者type的子類
因此metaclass的目的在類建立的時候自動的修改類,舉個例子,咱們想把一個類裏全部的屬性前面都加一個my_前綴,使用metaclass的方式就比較簡單
class MyAttrMetaclass(type): def __new__(cls, clsname, bases,dct): my_attr = {} for name, val in dct.items(): if not name.startswith('__'): my_attr["my_"+name] = val else: my_attr[name] = val return type.__new__(cls, clsname, bases, my_attr) class Foo(): __metaclass__= MyAttrMetaclass test_age = 1 test_name = "test" print(hasattr(Foo,"test_age")) False print(hasattr(Foo,"my_test_age")) True
能夠看到經過元類的方式,咱們的類Foo的屬性被修改了。
最後一個問題就是咱們在什麼狀況下會用到metaclass呢?
常見的例子有Django ORM 的Model類,
咱們定義一個Person類集成Model
class Person(Model): name = models.CharField(max_length=30) age = models.IntegerField() p = person(name="haha",age="31")
p.age 返回的是int 而不是IntegerField(),這就是由於在Model中使用的metaclass動態修改類
本文總結了黑魔法metaclass的定義,用法,主要參考了http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python