是否可以从外部模块修改元类?

Is modifying a metaclass from an external module possible?

让我们有一个名为 fields.py 的外部模块,它带有一个 metaclass FieldModelMetaclass 改变 class FieldModel:

# module fields.py
class FieldModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # code to alter class creation

class FieldModel(object):
    __metaclass__ = FieldModelMetaclass
    print 'run at parse time BEFORE metaclass applies'

# module consumer.py
import fields

def adjust_metaclass_new(cls, name, bases, attrs):
  # do an extra work on class `cls' and attributes `attrs'

# Is somehow possible from here alter `FieldModelMetaclass.__new__`
# by injection of adjust_metaclass_new to modify FieldModel
# before it gets instantiated ?
mymodel = fields.FieldModel()

据我所知,class 的 metaclass 在 编译 运行时生效,所以在我导入模块的那一刻where 被定义,class 已经受到影响。

如何在从外部模块创建 class 时拦截 metaclass 的效果?

在这种情况下,您无法轻易拦截 MetaClass 的使用。 FieldModelMetaclass.__new__ 方法在 class FieldModel 主体完成后立即调用,当导入模块时(因此在 运行时 ,而不是编译时)。

理论上您可以使用 sys.setrace() hook 在元 class 创建之后但在 class 语句执行之前注入额外的 Python 代码,但是这样疯狂的谎言。

另一个理论上的选择是解析模块源代码,重写它(使用 ast module),但同样,这种方式更疯狂。

您可以只向元class添加一个__call__方法,或者向使用元class创建的每个class添加一个__new__方法,如果你想要的只是拦截新实例的创建:

import fields

def metaclass__call__(cls, *args, **kw):
    instance = super(FieldModelMetaclass, cls).__call__(*args, **kw)
    # do something to the instance
    return instance

FieldModelMetaclass.__call__ = metaclass__call__

如果您的目标是更改 FieldModelMetaclass 生成 class 对象的方式,那么您最好的选择是在导入后再次更改 class 对象。您始终可以向 class 添加更多属性,或者使用您自己的元 class.

将 class 替换为其他属性