python黑魔法metaclass

python黑魔法metaclass

在看Flask源码的时候遇到了metaclass,记录下metaclass简单使用。

利用metaclass创建类示例01:

"""
class Foo(object):
    pass

以上代码解释器将其解释为
Foo = type('Foo', (object,), {})
type()的三个参数:'Foo':类名; (object, ): 类的继承关系,用元组表示; {}: 类的字段,方法。
"""


class MyType(type):
    def __new__(cls, *args, **kwargs):
        print('MyType __new__')
        return super(MyType, cls).__new__(cls, *args, **kwargs)

    def __init__(cls, *args, **kwargs):
        print('MyType __init__')
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        print('MyType __call__')
        # return None
        return super().__call__(*args, **kwargs)


class Foo(metaclass=MyType):
    pass


obj = Foo()
print(obj)


"""
MyType __new__
MyType __init__
MyType __call__
<__main__.Foo object at 0x0000020A6CDBAB00>
"""
当执行到class Foo(metaclass=MyType)语句时,会看是否指定元类,如果没指定元类则默认使用type创建类,否则按照指定元类创建类。这里回去执行MyType的__new__方法和__init__方法生成类。当执行obj = Foo()实例化类的时候会调用MyType的__call__方法。这里如果我在MyType里return None那么obj就会是None而不是类实例

给创建的类添加__call__方法,当执行对象obj()调用时执行。

class MyType(type):
    def __new__(cls, *args, **kwargs):
        print('MyType __new__')
        return super(MyType, cls).__new__(cls, *args, **kwargs)

    def __init__(cls, *args, **kwargs):
        print('MyType __init__')
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        print('MyType __call__')
        return super().__call__(*args, **kwargs)


class Foo(metaclass=MyType):
    def __call__(self, *args, **kwargs):
        print(11111)


obj = Foo()
print(obj)
print(obj())

"""
MyType __new__
MyType __init__
MyType __call__
<__main__.Foo object at 0x00000159DC30ABA8>
11111
None
"""

利用metaclass创建类示例02:

class MyType(type):
    def __new__(cls, *args, **kwargs):
        print('MyType __new__')
        return super(MyType, cls).__new__(cls, *args, **kwargs)

    def __init__(cls, *args, **kwargs):
        print('MyType __init__')
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        print('MyType __call__')
        return super().__call__(*args, **kwargs)


def with_meta(meta, Base):
    return meta('Foo', (Base, ), {})


Foo = with_meta(MyType, object)
print(Foo())


"""
MyType __new__
MyType __init__
MyType __call__
<__main__.Foo object at 0x000001D13919AC18>
"""

利用metaclass构造单例

class Sington(type):
    _instaces = dict()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instaces:
            cls._instaces[cls] = super().__call__(*args, **kwargs)
        return cls._instaces[cls]


class MyClass(metaclass=Sington):
    pass


one = MyClass()
two = MyClass()
print(id(one))
print(id(two))

posted @ 2019-04-23 16:15  村口王铁匠  阅读(193)  评论(0)    收藏  举报