pythonclassdecoratorself

Python decorators in classes


Can one write something like:

class Test(object):
    def _decorator(self, foo):
        foo()

    @self._decorator
    def bar(self):
        pass

This fails: self in @self is unknown

I also tried:

@Test._decorator(self)

which also fails: Test unknown

I would like to temporarily change some instance variables in the decorator and then run the decorated method, before changing them back.


Solution

  • Would something like this do what you need?

    class Test(object):
        def _decorator(foo):
            def magic( self ) :
                print "start magic"
                foo( self )
                print "end magic"
            return magic
    
        @_decorator
        def bar( self ) :
            print "normal call"
    
    test = Test()
    
    test.bar()
    

    This avoids the call to self to access the decorator and leaves it hidden in the class namespace as a regular method.

    >>> import stackoverflow
    >>> test = stackoverflow.Test()
    >>> test.bar()
    start magic
    normal call
    end magic
    >>> 
    

    edited to answer question in comments:

    How to use the hidden decorator in another class

    class Test(object):
        def _decorator(foo):
            def magic( self ) :
                print "start magic"
                foo( self )
                print "end magic"
            return magic
    
        @_decorator
        def bar( self ) :
            print "normal call"
    
        _decorator = staticmethod( _decorator )
    
    class TestB( Test ):
        @Test._decorator
        def bar( self ):
            print "override bar in"
            super( TestB, self ).bar()
            print "override bar out"
    
    print "Normal:"
    test = Test()
    test.bar()
    print
    
    print "Inherited:"
    b = TestB()
    b.bar()
    print
    

    Output:

    Normal:
    start magic
    normal call
    end magic
    
    Inherited:
    start magic
    override bar in
    start magic
    normal call
    end magic
    override bar out
    end magic