Class Decorators, Inheritance, super(), and maximum recursion

前端 未结 5 1809
故里飘歌
故里飘歌 2020-12-31 19:52

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

5条回答
  •  清酒与你
    2020-12-31 20:59

    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.

提交回复
热议问题