元類在不少編程語言中都有這樣的概念,咱們都知道,類能夠建立對象,類自己也是對象,既然是對象,那麼它確定也是被創造出來的,元類就專門用來創造類對象,因而,這就給咱們提供了一種操縱或者監聽類的能力。python
平時咱們建立一個類,使用的是這種方式:編程
class MyClass(object): def method(self): return 1 instance1 = MyClass() print(instance1.method())
若是把類也當作一個對象,利用元類,咱們這樣建立一個類:編程語言
def method(self): return 1 klass = type('MyClass', (object,), {'method': method}) instance1 = klass() print(instance1.method())
若是從寫法上看,沒什麼太大的區別,MetaClass真正有用的地方是,咱們能夠自定義元類,接下來咱們看一段代碼:spa
class RevealingMeta(type): def __new__(mcs, name, bases, namespace, **kwargs): print(mcs, "__new__ called") return super().__new__(mcs, name, bases, namespace) @classmethod def __prepare__(metacls, name, bases, **kwargs): print(metacls, "__prepare__ called") return super().__prepare__(name, bases, **kwargs) def __init__(cls, name, bases, namespace, **kwargs): print(cls, "__init__ called") super().__init__(name, bases, namespace) def __call__(cls, *args, **kwargs): print(cls, "__call__ called") return super().__call__(*args, **kwargs)
上邊的代碼能夠算是固定寫法了,這其中比較重要的概念是這4個方法的調用時機:code
__new__
當某個類被建立的時候會調用__prepare__
在建立類的時候,能夠傳入額外的字典class Klass(metaclass=Metaclass, extra="value"):
,這個方法就是用來建立接收dict的,因此這個方法會在__new__
前邊調用__init__
這個方法算是對__new__
的一些補充__call__
這個方法會在類被建立的時候調用咱們就利用上邊代碼建立出來的元類,建立一個類:對象
class RevealingMeta(type): def __new__(mcs, name, bases, namespace, **kwargs): print(mcs, "__new__ called") return super().__new__(mcs, name, bases, namespace) @classmethod def __prepare__(metacls, name, bases, **kwargs): print(metacls, "__prepare__ called") return super().__prepare__(name, bases, **kwargs) def __init__(cls, name, bases, namespace, **kwargs): print(cls, "__init__ called") super().__init__(name, bases, namespace) def __call__(cls, *args, **kwargs): print(cls, "__call__ called") return super().__call__(*args, **kwargs) class RevealingClass(metaclass=RevealingMeta): def __new__(cls, *args, **kwargs): print(cls, "__new__ called") return super().__new__(cls) def __init__(self): print(self, "__init__ called") super().__init__()
若是這時候直接執行代碼,會打印出:it
<class '__main__.RevealingMeta'> __prepare__ called <class '__main__.RevealingMeta'> __new__ called <class '__main__.RevealingClass'> __init__ called <class '__main__.RevealingClass'> __call__ called
這說明,只要建立了類就會調用上邊的方法,這些方法的調用跟實例的建立沒有關係,接下來執行:class
instance12 = RevealingClass()
在上邊打印的後邊,會打印出:object
<class '__main__.RevealingClass'> __new__ called <__main__.RevealingClass object at 0x104032048> __init__ called
這就是元類的基本用法了,它通常會用在不少的framework中,但也容易出錯,咱們能夠爲某個類隨意指定元類,若是該元類沒有實現這些方法,就有可能會出現崩潰。meta