I\'m trying to figure out how to use decorators on subclasses that use super(). Since my class decorator creates another subclass a decorated class seems to pre
As you might already be aware, the problem arises from the fact that the name SubClassAgain in SubClassAgain.print_class is scoped to the current module's global namespace. SubClassAgain thus refers to the class _DecoratedClass rather than the class that gets decorated. One way of getting at the decorated class is to follow a convention that class decorators have a property referring to the decorated class.
def class_decorator(cls):
class _DecoratedClass(cls):
original=cls
def __init__(self):
print '_DecoratedClass.__init__'
return super(_DecoratedClass, self).__init__()
return _DecoratedClass
@class_decorator
class SubClassAgain(BaseClass):
original
def print_class(self):
super(self.__class__.original, self).print_class()
Another is to use the __bases__ property to get the decorated class.
@class_decorator
class SubClassAgain(BaseClass):
def print_class(self):
super(self.__class__.__bases__[0], self).print_class()
Of course, with multiple decorators, either of these become unwieldy. The latter also doesn't work with subclasses of the decorated class. You can combine decorators and mixins, writing a decorator that adds a mixin into a class. This won't help you override methods.
def class_decorator(cls):
class _DecoratedClass(object):
def foo(self):
return 'foo'
cls.__bases__ += (_DecoratedClass, )
return cls
Lastly, you can work directly with the class attributes to set methods.
def class_decorator(cls):
old_init = getattr(cls, '__init__')
def __init__(self, *args, **kwargs):
print 'decorated __init__'
old_init(self, *args, **kwargs)
setattr(cls, '__init__', __init__)
return cls
This is probably the best option for your example, though the mixin-based decorator also has its uses.