Since a class object is created after the body is executed, it can't be available to the class body. Even the name is unavailable, at least by default. However, you can use the __prepare__()
method in a metaclass to stick it in there. This recipe is a simple demonstration of how.
1 2 3 4 5 6 7 8 9 | class Meta(type):
@classmethod
def __prepare__(meta, name, bases, **kwargs):
return {"__name__": name}
class X(metaclass=Meta):
print(locals())
#{'__name__': 'X', '__module__': 'X', '__locals__': {...}}
|
When a class definition is evaluated, the following happens (roughly):
- the base classes and metaclass are evaluated[1],
<metaclass>.__prepare__(name, bases, **kwargs)
is called to generate a mutable mapping (call it <namespace>),- if a docstring is in the class definition,
<namespace>["__doc__"]
is set to it, - the class body is exec'ed separately, using <namespace> as the frame locals,
<metaclass>(name, bases, <namespace>)
is called[2],<metaclass>.__new__(<metaclass>, name, bases, <namespace>)
is called and returns a new[3] object (and the contents of <namespace> are copied into<class>.__dict__
),- if the new object is an instance of <metaclass>,
<metaclass>.__init__(cls, name, bases, <namespace>)
is called. - the new object is returned,
- the object from (5) is bound in the namespace where the class was defined.
This demonstrates that when the class body is exec'ed the class object does not exist yet (and so cannot be referenced there). The class's name, which _is_ around, is also not available. This recipe shows how to make it available.
[1] the default metaclass is type
.
[2] this is the same way you instantiate any class (i.e. <class>.__call__(...)
is called). The difference is that in this case <class>
is a metaclass (subclass of type
) and the instance is a class object.
[3] it actually isn't necessarily a new object. It could be any object. However, by default (and normally) it will be a new instance of <metaclass>.
If you just want a
__name__
attribute to be available on class instances, you can also inherit from the following class:That's a helpful class, but unrelated to the recipe. I'll update the discussion section to clarify.
using
metaclass
in that way applies only to python 3. In python 2, the metaclass only gets access to the body after the body has been evaluated; And requiring a specific metaclass for this is probably inconvenient, since you might really want to use another metaclass instead.The alternative is to fetch the class name yourself:
Very true. In Python 2 have less options. I have used something similar, though with the inspect module:
inspect.currentframe().f_code.co_name
.For this recipe my motivation was to avoid frame-iness, because that route is (technically) CPython specific; the language reference says nothing about executing a class body via a code object. However, I gladly admit that is a weak objection since most other implementations work pretty hard to be compatible with CPython when possible. Also, this recipe relies on Python 3, which is still mostly just CPython anyway. :)
As to metaclasses, you're right that it would be less convenient to use this one exclusively. If you want to use another metaclass, you write one that subclasses the one you want to use. Then you throw the
__prepare__
on that subclass.