美文网首页
Python元类编程 之 new、init、call

Python元类编程 之 new、init、call

作者: Gascognya | 来源:发表于2020-11-21 16:19 被阅读0次

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

    class Demo:
        def __new__(cls, *args, **kwargs):
            return super().__new__(cls, *args, **kwargs)
    
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            pass
    

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

    • __ new __() 代表 类对象 产生 实例对象 的过程。实例对象 在这里被生产并 return 回去
    • __ init __() 代表 实例对象 初始化的过程,也称构造函数
    • __ call __() 代表 实例对象 被调用的行为

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

    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)
    

    我们同样可以推断出

    • __ new __() 代表 元类对象 产生 类对象 的过程。类对象 在这里被生产并 return 回去
    • __ init __() 代表 类对象 初始化的过程,也称构造函数
    • __ call __() 代表 元类对象 被调用的行为

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

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

    • __ call __()是被对象被调用时的行为,当我们使用 类对象 来创建新实例时。本质就是调用 类对象 的行为。
      例如d = Demo(),在此时, 类对象 的call就被调用了。那么call产生的结果是什么?,是创建 实例对象 且初始化。
      所以我们就可以推断出,类对象的call实际内容为
        def __call__(cls, *args, **kwargs):
            instance = cls.__new__(cls)
            instance.__init__(*args, **kwargs)
            return instance
            # return super().__call__(*args, **kwargs)
    
    • __ new __() 这是我们在metaclass中最常用的方法,他代表的 元类对象 产生其 实例(类对象) 的过程
    • __ init __() 类对象的init并不常见,其中最大的问题是,我们定义class的时候,并没有显示的传参过程。
      实际上我们在类对象中定义的参数,都会经过init。
    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帮我们自行实现了。例如定义类时,会自动执行元类的实例化。

    相关文章

      网友评论

          本文标题:Python元类编程 之 new、init、call

          本文链接:https://www.haomeiwen.com/subject/ywheiktx.html