分享

python3元类的调用顺序

 印度阿三17 2019-06-07

在尝试理解元类创建类实例的顺序时,我感到困惑.根据该图(source),enter image description here

我键入以下代码进行验证.

class Meta(type):
    def __call__(self):
        print("Meta __call__")
        super(Meta, self).__call__()

    def __new__(mcs, name, bases, attrs, **kwargs):
        print("Meta __new__")
        return super().__new__(mcs, name, bases, kwargs)

    def __prepare__(msc, name, **kwargs):
        print("Meta __prepare__")
        return {}

class SubMeta(Meta):
    def __call__(self):
        print("SubMeta __call__!")
        super().__call__()

    def __new__(mcs, name, bases, attrs, **kwargs):
        print("SubMeta __new__")
        return super().__new__(mcs, name, bases, kwargs)

    def __prepare__(msc, name, **kwargs):
        print("SubMeta __prepare__")
        return Meta.__prepare__(name, kwargs)

class B(metaclass = SubMeta):
    pass

b = B()

但是,结果似乎不是这样的.

SubMeta __prepare__
Meta __prepare__
SubMeta __new__
Meta __new__
SubMeta __call__!
Meta __call__

任何帮助将不胜感激.

解决方法:

尽管@ torek的长篇答案,以及关于课堂创作的许多其他细节,你在这个问题上汇集的内容大多是正确的.

你的代码中唯一错误的就是让你感到困惑的是你调用Meta的te类本身就是SubMeta的元类,而不是它的父元素.

只需将Submeta声明更改为:

class SubMeta(type, metaclass=Meta):
    ...

(也不需要它继承“Meta” – 它只能从类型派生.除此之外,我想要定制类型.__ call__,这对于创建类的实例同时是有用的(当调用SubMeta .__ call__时,你的类本身(调用Meta .__ call__))

这是我刚在终端输入的另一个较短的例子.很抱歉命名不一致,并且不太完整 – 但它显示了要点:

class M(type):
    def __call__(mmcls, *args, **kwargs):
        print("M's call", args, kwargs)
        return super().__call__(*args, **kwargs)

class MM(type, metaclass=M):
    def __prepare__(cls, *args, **kw):
        print("MM Prepare")
        return {}
    def __new__(mcls, *args, **kw):
        print("MM __new__")
        return super().__new__(mcls, *args, **kw)

class klass(metaclass=MM):
    pass

在处理klass体时,Python输出是:

MM Prepare
M's call ('klass', (), {'__module__': '__main__', '__qualname__': 'klass'}) {}
MM __new__

此外

正如您所看到的,使用元元类,可以自定义元类__init__和__new__的调用顺序和参数,但仍然存在无法从纯Python代码自定义的步骤,并且需要对API的本机调用(以及可能的原始对象结构操作) – 即:

>无法控制对__prepare__的调用
>无法控制对创建的类的__init_subclass__的调用
>可以控制何时调用描述符’__set_name__

最后两个项目发生在meta-meta的__call__返回之后,并且在将流程恢复到类模块所在的模块之前.

来源:http://www./content-1-228701.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多