Question

Is it possible to somehow configure a python module or REPL to use a default metaclass for all classes defined, regardless of whether or not a metaclass is used in the class ?

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        setattr(cls, "_test_member", "test_value")

class A(object):
    pass

>>> A._test_member
'test_value'
Was it helpful?

Solution

Using Pavel Anossov's (now deleted) comment:

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        cls._test_member = "test_value"

object = met('object', (object,), {})

class A(object):
    pass

print(A._test_member)

prints

test_value

Note that a class can have only one metaclass. (Since, after all, any object can have only one type). But additionally, the metaclass of a class must be a (non-strict) subclass of the metaclasses of all its bases. In other words, the class's metaclass and the metaclasses of all its bases must either be the same, or all those metaclasses must be subclasses of each other. So the above solution may not work if a class tries to use a metaclass which is not a subclass of met.

For example,

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        cls._test_member = "test_value"

object = met('object', (object,), {})

class someothertype(type): pass

class B(object):
    __metaclass__ = someothertype

raises

TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

OTHER TIPS

On python 2.x you could just do

 __metaclass__ = met

in the beginning of the module and then define your class in old style mode:

class A:
    pass

On 3.x, this is no longer possible. Also, "Explicit is better than implicit."

Another approach, you could do:

class Object(metaclass=met):  # Py3k syntax
    pass

and always inherit from it.

Note: Calling the subclass of type is the only way to make use of metaclass compatible with both Py2k and Py3k. Like in unutbu's answer

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top