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'
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?
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:
But if you insist on changing the metaclass dynamically, you first need to define B with a temporary custom metaclass:
Then you can define the metaclass like that:
And then do something like:
You also need to make sure that all the initialization of the class is done
_actual_init. You can also add aclassmethodto the metaclass that changes the metaclass for you.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.