python中MetaClass的一些用法

元类在很多编程语言中都有这样的概念,我们都知道,类可以创建对象,类本身也是对象,既然是对象,那么它肯定也是被创造出来的,元类就专门用来创造类对象,于是,这就给我们提供了一种操纵或者监听类的能力。

平时我们创建一个类,使用的是这种方式:

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真正有用的地方是,我们可以自定义元类,接下来我们看一段代码:

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个方法的调用时机:

  • __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__()

如果这时候直接执行代码,会打印出:

<class '__main__.RevealingMeta'> __prepare__ called
<class '__main__.RevealingMeta'> __new__ called
<class '__main__.RevealingClass'> __init__ called
<class '__main__.RevealingClass'> __call__ called

这说明,只要创建了类就会调用上边的方法,这些方法的调用跟实例的创建没有关系,接下来执行:

instance12 = RevealingClass()

在上边打印的后边,会打印出:

<class '__main__.RevealingClass'> __new__ called
<__main__.RevealingClass object at 0x104032048> __init__ called

这就是元类的基本用法了,它一般会用在很多的framework中,但也容易出错,我们可以为某个类随意指定元类,如果该元类没有实现这些方法,就有可能会出现崩溃。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.元类 1.1.1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这...
    TENG书阅读 5,121评论 0 3
  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 19,256评论 17 410
  • 学会倾听是宽容的表现,它饱含着爱。用心去倾听感受不一样的生活。 古人说过“听君一席话,胜读十年书”认真倾听别...
    諪諪_0c2f阅读 1,664评论 0 0
  • 最近因为失恋有拾起未读完的《完美关系的秘密》,同时再读《5分钟商学院商业篇》。有意思的发现,事情的普遍相通性...
    瑾姑娘的猫咪世界阅读 9,140评论 0 1
  • 其实很多人想到过死吧,那是我们内心中,最隐秘、最不敢开口的秘密吧。我想过很多次了,在身边的人都过得很开心的...
    小跑儿阅读 2,801评论 0 0