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

相關文章
相關標籤/搜索