让我们有一个名为fields.py的外部模块,该模块具有一个可替换类FieldModelMetaclass的元类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()


据我所知,类的元类在编译时会起作用,因此,当我导入定义了模块的模块时,类已经受到影响。

在从外部模块创建类时,如何截获元类的作用?

最佳答案

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

从理论上讲,您可以在创建元类之后但在执行sys.setrace()语句之前,使用class hook注入其他Python代码,但这种方式可以消除疯狂。

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

如果您只想拦截新实例的创建,则可以只向元类添加__call__方法,或向由元类创建的每个类添加__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生成类对象的方式,那么最好的选择是在导入后再次更改类对象。您总是可以向该类添加更多属性,或者使用自己的元类将其替换为其他属性。

关于python - 是否可以从外部模块修改元类?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30213620/

10-16 22:16