如果 MyMeta 是 Python 3.x 中的 MyClass 元类,MyMeta 可以对 MyClass 进行哪些类型的操作?

If MyMeta is the MyClass metaclass in Python 3.x, what types of manipulation can MyMeta do with MyClass?

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

假设 class MyMeta 是 class MyClass 的元class。

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

即使subclass metaclass不是MyMeta,继承MyClass时是否可以调用MyMeta的方法?

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

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

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

Can MyMeta generate code in MyClass that intercepts get and set of MyClass instance attributes?

是的。这可以通过在 class 中注入 __getattribute____setattr__ 方法来完成。但是,如果属性以其他形式声明(例如,带有注释),它还可以为每个属性创建描述符以仅处理对这些属性的更改。但是,如果只是以 classic 方式定义,在代码中设置 class' __init__ (但第一种方法无论如何涵盖所有属性);

Can a method of MyMeta be called when MyClass is inherited, even if the subclass metaclass is not MyMeta?

子class 将自动继承 MyMeta 作为其元classes。如果因为其他的基产生冲突,当使用多重继承时,有其他的metaclasses,subclass根本无法创建。 (除非有人创建一个合适的 metaclass 继承自两个 metaclasses,也就是说)。 _TL;DR:是的。不,没有 subclass 的 metaclass 与其父项不同。

Can a method of MyMeta be called when a MyClass method is overridden in a subclass, even if the subclass metaclass is not MyMeta?

没有"subclass's metaclass not being MyMeta"这样的东西。接着, metaclass 作用于 subclass 创建并且可以检测方法覆盖。而且,甚至可以在创建 class 之后通过猴子修补来检测方法覆盖(通过让 metaclass 实现 __setattr__

Can a method of MyMeta be called when a method of MyClass uses an attribute that has not been declared?

是的,通过设置合适的 __getattribute____setattr__ 方法,如前所述。对此没有现成的功能(也不需要元class,只需实现这两种方法的混合即可)

Can MyMeta handle the AST of MyClass or another equivalent representation? For example, can MyMeta check if each class method has at most 20 statements? Or add a statement after the second method statement? Or rename a method?

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

一种更符合 Python 风格的方法是使用装饰器,并使用元class 在方法上自动应用装饰器。如果需要,这些装饰器可以为 运行 前导码和 post 调用代码提供包装函数。