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?)