元类在不少编程语言中都有这样的概念,咱们都知道,类能够建立对象,类自己也是对象,既然是对象,那么它确定也是被创造出来的,元类就专门用来创造类对象,因而,这就给咱们提供了一种操纵或者监听类的能力。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