huin's answer is very good. His two options execute decorator code only when the decorated function is defined (that's not a criticism, as often that's exactly what you want). Here's an extension of his class-based approach, which also executes some code each time you call the function. This is the sort of thing you do, for example, when you are using decorators to ensure thread safety.
class MyInnerDecorator:
def __init__( self, outer_decorator, *args, **kwargs ):
self._outerDecorator = outer_decorator
self._args = args
self._kwargs = kwargs
def __call__( self, f ):
print "Decorating function\n"
self._f = f
return self.wrap
def wrap( self, *args, **kwargs ):
print "Calling decorated function"
print "Debug is ", self._outerDecorator._debug
print "Positional args to decorator: ", self._args
print "Keyword args to decorator: ", self._kwargs
print "Positional args to function call: ", args
print "Keyword args to function call: ", kwargs
return self._f( *args, **kwargs )
print "\n"
class MyDecorator:
def __init__( self, debug ):
self._debug = debug
def myFunc( self, *args, **kwargs ):
return MyInnerDecorator( self, "Wrapped by myFunc", *args, **kwargs )
def myOtherFunc( self, *args, **kwargs ):
return MyInnerDecorator( self, "Wrapped by myOtherFunc", *args, **kwargs )
bar = MyDecorator( debug=True )
@bar.myFunc( a=100 )
def spam( *args, **kwargs ):
print "\nIn spam\n"
@bar.myOtherFunc( x=False )
def eggs( *args, **kwargs ):
print "\nIn eggs\n"
spam( "penguin" )
eggs( "lumberjack" )
Which outputs this:
Decorating function
Decorating function
Calling decorated function
Debug is True
Positional args to decorator: ('Wrapped by myFunc',)
Keyword args to decorator: {'a': 100}
Positional args to function call: ('penguin',)
Keyword args to function call: {}
In spam
Calling decorated function
Debug is True
Positional args to decorator: ('Wrapped by myOtherFunc',)
Keyword args to decorator: {'x': False}
Positional args to function call: ('lumberjack',)
Keyword args to function call: {}
In eggs