3

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'
0

2 Answers 2

4

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
Sign up to request clarification or add additional context in comments.

3 Comments

I didn't know you can redefine object using itself as a base. Very sneaky.
@unutbu: I replaced setattr(cls, "_test_member", "test_value") with its more usual and direct form.
+1: this works even if the class defines __metaclass__, as the question required.
3

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

5 Comments

Is there a way to redefine the builtin object class to use a metaclass?
you can rebind it, like said in a comment above: object = Object
That would be incredibly dangerous, error-prone, and generally undesirable.
@user2357112 Yes, that's why I would name it with a capital O, so other people can know whats going on
@dilbert: Your question asked for met to be the meta-class, regardless of whether or not a metaclass is used in the class. Note that this answer does not work for Python 2 in the case of a class that defines an explicit metaclass. unutbu's method work in this case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.