【问题标题】:If MyMeta is the MyClass metaclass in Python 3.x, what types of manipulation can MyMeta do with MyClass?如果 MyMeta 是 Python 3.x 中的 MyClass 元类,MyMeta 可以对 MyClass 进行哪些类型的操作?
【发布时间】:2020-07-21 00:17:31
【问题描述】:

我们的目标是将 Python 元类的功能与其他语言的元编程系统进行比较,例如 Groovy、Xtend、Nemerle、CLOS、OpenJava、BSJ (BackStage Java)、Iguana/J、Scala、Cyan 的编译器插件等。

假设类 MyMeta 是类 MyClass 的元类。

MyMeta 能否在 MyClass 中生成拦截获取和设置 MyClass 实例属性的代码?

MyClass被继承时是否可以调用MyMeta的方法,即使子类元类不是MyMeta?

在子类中重写 MyClass 方法时是否可以调用 MyMeta 的方法,即使子类元类不是 MyMeta?

MyClass的方法使用未声明的属性时,是否可以调用MyMeta的方法?

MyMeta 能否处理 MyClass 的 AST 或其他等效表示? 例如,MyMeta 是否可以检查每个类方法是否最多有 20 条语句?或者在第二个方法语句之后添加一个语句?或者重命名一个方法?

【问题讨论】:

    标签: python reflection metaprogramming metaclass


    【解决方案1】:

    MyMeta 能否在 MyClass 中生成拦截 get 和 set 的代码 MyClass 实例属性?

    是的。这可以通过在类中注入__getattribute____setattr__ 方法来完成。但是如果属性以其他形式声明(例如,使用注释),它还可以为每个属性创建描述符以仅处理对这些属性的更改。但是,如果这些“实例属性”只是以经典方式定义,在代码中设置,在类 __init__ 内(但第一种方法无论如何涵盖所有属性),它就不能轻易猜测什么是单独的“实例属性”;

    MyClass 被继承时是否可以调用 MyMeta 的方法,即使 子类元类不是 MyMeta?

    子类将自动继承 MyMeta 作为它们的元类。如果由于其他基础而发生冲突,在使用多重继承时,具有其他元类,则根本无法创建子类。 (除非创建一个从两个元类继承的合适的元类,即)。 _TL;博士:是的。不,没有子类的元类与其父类不同。

    MyClass 方法被覆盖时是否可以调用 MyMeta 的方法 在子类中,即使子类元类不是 MyMeta?

    没有“子类的元类不是 MyMeta”这样的事情。然后, 元类作用于子类的创建,并且可以检测方法覆盖。而且,它甚至可以在创建类后通过猴子修补来检测方法覆盖(通过让元类实现__setattr__

    当 MyClass 的方法使用 尚未声明的属性?

    是的,通过设置合适的__getattribute____setattr__ 方法,如前所述。没有现成的功能(也不需要元类,只需一个实现这两种方法的 mixin 就可以了)

    MyMeta 能否处理 MyClass 的 AST 或其他等价物 表示?例如,MyMeta 是否可以检查每个类方法是否有 最多20个语句?或者在第二种方法后加一条语句 陈述?或者重命名一个方法?

    在创建 AST 并将其烘焙成字节码之后调用元类。但它可以自省到方法字节码以检查它想要的任何东西,它可以获取它们的源代码(如果可用),并重新生成 AST,它可以重新创建其他方法来替换原始方法——替代品具有所有——新的字节码。 然而,这种东西很少使用,如果曾经使用过,而且听起来有点矫枉过正。

    更 Python 的方法是使用装饰器,并使用元类在方法上自动应用装饰器。如果需要,这些装饰器可以提供包装函数来运行每个方法的前导码和调用后代码。

    【讨论】:

    • 非常感谢,@jsbueno 非常详细的回答。我很感激,因为它在有关 Cyan 语言的元对象协议 (cyan-lang.org) 的文章中很有用。
    • >子类将自动继承 MyMeta 作为它们的 >metaclasses。但是子类元类可以从超类元类继承,如this example 所示。子类元类可以重新定义与超类元类有关的一切。效果与使用不同的元类相同。因此,我想当类被继承时,没有一定的方法可以调用元类方法。对吗?
    • 出于同样的原因,我想在子类中重写类方法时,没有确定的方法可以调用元类方法。这是正确的吗?
    • setattr 不是仅用于属性吗?它可以用来检测你写的方法覆盖吗?
    • 如果有一个子元类专门设计用于“对抗”它继承的基元类,那么显然可以避免该基元类上的任何内容生效。但是你在这里陷入了军备竞赛,例如,如果子类的程序员想要对元类警察状态隐藏一些东西。除了打代码或其他东西之外,这没有任何意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多