是否可以从外部模块修改元类?
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 替换为其他属性
让我们有一个名为 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.