python中MetaClass的一些用法

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

相关文章
相关标签/搜索