How to determine the metaclass of a class?

class, metaclass, python, python-3.x

Solution

Ok - so, a class's metaclass is just its own "type", and can be given by `type(cls)` and other means such as `cls.__class__`.

In Python 3.x there are no further ambiguities - as the syntax for creating a metaclass just passes it as a named parameter on the class declaration statement anyway.

However, the syntax used for creating a metaclass in Python 2.x generates a side-effect that is worth noting.

Upon doing

class A(object):
    __metaclass__ = MyMeta

The `__metaclass__` attribute is set to that value in the actual class, even if the actual metaclass is another one.

Consider:

def class_pre_decorator(name, bases, namespace):
     # do something with namespace
     return type(name, bases, namespace)

This is a callable that can be used in the metaclass declaration of both Python 2 and 3 - and it is valid. After resolving, the actual metaclass in both cases will simply be `type`. However, in Python 2.x, `cls.__metaclass__` will point to the callable `class_pre_decorator`, even tough `type(cls)` returns `type`, which is the correct metaclass.(Note that using callables in this way, they will not be used agian when the class is further subclassed)

There is no way in Python 3 to guess the callable actually used to instantiate a class if it gives no other hint (like setting an attribute on the class) that it was used:

# python 2
class A(object):
   __metaclass__ = class_pre_decorator

On the console:

In [8]: type(A)
Out[8]: type

In [9]: A.__metaclass__
Out[9]: <unbound method A.class_pre_decorator>

and

# Python 3
class A(metaclass=class_pre_decorator):
    pass

And trying to read `A.__metaclass__` will simply raise an AttributeError.

Problem

I have a class object, `cls`. I want to know its metaclass. How do I do this? (If I wanted to know its parent classes, I would do `cls.__mro__`. Is there something like this to get the metaclass?)

Original source

Related problems