Python元类编程 之 new、init、call

2020-11-21  本文已影响0人  Gascognya

首先我们知道,实例衍生自类对象,类对象衍生自元类对象

class Demo:
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        pass

这是一个普通的类对象,其中

类对象之于实例对象,正如元类对象之于类对象,他们之间的关系是完全相同的

class DemoMeta(type):
    def __new__(mcs, *args, **kwargs):
        return super().__new__(mcs, *args, **kwargs)

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

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

我们同样可以推断出

那么上述几个方法何时被调用?

我们不妨根据其作用来推断

    def __call__(cls, *args, **kwargs):
        instance = cls.__new__(cls)
        instance.__init__(*args, **kwargs)
        return instance
        # return super().__call__(*args, **kwargs)
class DemoMeta(type):
    def __init__(cls, *args, **kwargs):
        super().__init__(*args, **kwargs)

class Demo(metaclass=DemoMeta):
    num = 10

我们在metaclass的init处打断点,便可以看到num:10在参数当中

当然我们也可以手动定义类对象,就像创建实例那样简单

Demo = DemoMeta('Demo', (object,), {num: 10})
# 等价于
class Demo(metaclass=DemoMeta):
    num = 10

如果按类推,DemoMeta()是调用元类的__ call __()
没错,是这样,按理来说这是个无限的循环,当然实际上python解释器不会允许这样的情况。

无论是元类,类,实例,都不具有特殊性。他们都遵循着同样的行为

唯一的不同是,有些动作,python帮我们自行实现了。例如定义类时,会自动执行元类的实例化。

上一篇 下一篇

猜你喜欢

热点阅读