有没有一种方法可以在类定义之后设置元类? [英] Is there a way to set metaclass after the class definition?
问题描述
为了设置类的元类,我们使用__metaclass__
属性.元类是在定义类时使用的,因此在类定义之后显式设置它无效.
In order to set metaclass of a class, we use the __metaclass__
attribute. Metaclasses are used at the time the class is defined, so setting it explicitly after the class definition has no effect.
当我尝试显式设置元类时,会发生这种情况;
This is what happens when I try to set metaclasses explicitly;
>>> class MetaClass(type):
def __new__(cls, name, bases, dct):
dct["test_var"]=True
return type.__new__(cls, name, bases, dct)
def __init__(cls, name, bases, dct):
super(MetaClass, cls).__init__(name, bases, dct)
>>> class A:
__metaclass__=MetaClass
>>> A.test_var
True
>>> class B:
pass
>>> B.__metaclass__=MetaClass
>>> B.test_var
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
B.test_var
AttributeError: class B has no attribute 'test_var'
我能想到的最好的主意是重新定义整个类并以某种方式动态添加__metaclass__
属性.或者您知道在类定义之后设置元类的更好方法吗?
The best idea I can think of is to re-define whole class and add the __metaclass__
attribute dynamically somehow. Or do you know a better way set metaclass after the class definition?
推荐答案
创建类后,可以像更改对象的类一样更改元类,但是会遇到很多问题.对于初学者,初始元类必须与type
不同,新元类的__init__
和__new__
不会被调用(尽管您可以手动调用__init__
或执行__init__
的方法"的工作).
You can change the metaclass after class creation the same way that you can change the class of an object, however you'd have a lot of issues. For starters, the initial metaclass needs to be different from type
, the __init__
and __new__
of the new metaclass won't be called (though you can manually call __init__
or a method that performs __init__
's job).
更改元类的最麻烦的方法可能是从头开始重新创建该类:
Possibly the least troublesome way to change the metaclass is to recreate the class again from scratch:
B = MetaClass(B.__name__, B.__bases__, B.__dict__)
但是,如果您坚持动态更改元类,则首先需要使用临时自定义元类定义B:
But if you insist on changing the metaclass dynamically, you first need to define B with a temporary custom metaclass:
class _TempMetaclass(type):
pass
class B:
__metaclass__ = _TempMetaclass # or: type('temp', (type, ), {})
然后您可以像这样定义元类:
Then you can define the metaclass like that:
class MetaClass(type):
def __init__(cls, *a, **kw):
super(MetaClass, cls).__init__(*a, **kw)
cls._actual_init(*a, **kw)
def _actual_init(cls, *a, **kw):
# actual initialization goes here
然后执行以下操作:
B.__class__ = MetaClass
MetaClass._actual_init(B, B.__name__, B.__bases__, B.__dict__)
您还需要确保该类的所有初始化均已完成_actual_init
.您还可以在元类中添加classmethod
,从而为您更改元类.
You also need to make sure that all the initialization of the class is done _actual_init
. You can also add a classmethod
to the metaclass that changes the metaclass for you.
这两种解决方案都有一个缺点,即B的基数会受到限制-它们必须与原始和新的元类都兼容,但是我想这对您来说不是问题.
Both solutions have the slight shortcoming that B's bases would be limited - they need to be compatible with both the original and the new metaclass, but I guess that's not an issue in your case.
这篇关于有没有一种方法可以在类定义之后设置元类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!