I want to add an attribute for every class created by a metaclass. For example, when a class named C
is created, I want add an attribute C._C__sup
whose value is the descriptor super(C)
.
Here is what I've tried:
class Meta(type):
def __init__(cls, name, bases, dict): # Not overriding type.__new__
cls.__dict__['_' + name + '__sup'] = super(cls)
# Not calling type.__init__; do I need it?
class C(object):
__metaclass__ = Meta
c = C()
print c._C__sup
This gives me:
TypeError: Error when calling the metaclass bases
'dictproxy' object does not support item assignment
Some background information:
(You don't have to read this part)
Inspired by this article, what I'm doing is trying to avoid "hardcoding" the class name when using super
:
The idea there is to use the unbound super objects as private attributes. For instance, in our example, we could define the private attribute
__sup
in the classC
as the unbound super objectsuper(C)
:>>> C._C__sup = super(C)
With this definition inside the methods the syntax
self.__sup.meth
can be used as an alternative tosuper(C, self).meth
. The advantage is that you avoid to repeat the name of the class in the calling syntax, since that name is hidden in the mangling mechanism of private names. The creation of the__sup
attributes can be hidden in a metaclass and made automatic. So, all this seems to work: but actually this not the case.
Use setattr
instead of assignment to cls.__dict__
:
class Meta(type):
def __init__(cls, name, bases, clsdict): # Not overriding type.__new__
setattr(cls, '_' + name + '__sup', super(cls))
super(Meta, cls).__init__(name, bases, clsdict)
class C(object):
__metaclass__ = Meta
def say(self):
return 'wow'
class D(C):
def say(self):
return 'bow' + self.__sup.say()
c = C()
print(c._C__sup)
# <super: <class 'C'>, <C object>>
d = D()
print(d.say())
prints
bowwow
By the way, it is a good idea to call
super(Meta, cls).__init__(name, bases, clsdict)
inside Meta.__init__
to allow Meta
to participate in class hierarchies which
might need super
to properly call a chain of __init__
s. This seems
particularly appropriate since you are building a metaclass to assist with the
use of super
.