I was playing around with metaclasses in CPython 3.2.2, and I noticed it is possible to end up with a class that is its own type:
Python 3.2.2 (default, Sep 5 2011, 21:17:14)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class MC(type): #a boring metaclass that works the same as type
... pass
...
>>> class A(MC, metaclass=MC): #A is now both a subclass and an instance of MC...
... pass
...
>>> A.__class__ = A #...and now A is an instance of itself?
>>> A is type(A)
True
For our metaclass A
, there doesn't really seem to be much of a distinction between class and instance attributes:
>>> A.__next__ = lambda self: 1
>>> next(A)
1 #special method lookup works correctly
>>> A.__dict__
dict_proxy({'__module__': '__main__',
'__next__': <function <lambda> at 0x17c9628>,
'__doc__': None})
>>> type(A).__dict__
dict_proxy({'__module__': '__main__',
'__next__': <function <lambda> at 0x17c9628>,
'__doc__': None}) #they have the same `__dict__`
All this works the same (apart from changing to __metaclass__
, and __next__
not being a special method) in CPython 2.7.2, PyPy 1.6.0 (which implements Python 2.7.1), and Jython 2.2.1 (no idea what Python version that is, if any - I'm not very familiar with Jython).
I can't find much explanation about the conditions under which assigning to __class__
is allowed (apparently the types concerned must be user-defined and have a similar layout in some sense?). Note that A
does have to be both a subclass and an instance of MC
for the assignment to __class__
to work. Are recursive metaclass hierarchies like this really supposed to be acceptable? I'm very confused.
Recursive metaclass hierachies are actually part of the language core:
>>> type(type)
<class 'type'>
So even the standard metaclass type
is its own type. There is no conceptual problem with this construct – it just means the __class__
attribute of the class points to the class itself.
Assignments to the __class__
attribute are only allowed for user-defined classes. The assignment is legal if either both the original class and the new class do not define __slots__
, or both set __slots__
to the same sequence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With