Хуин ответил очень хорошо. Его две опции выполняют код декоратора только тогда, когда определена декорированная функция (это не критика, а часто именно то, что вы хотите). Вот расширение его подхода на основе классов, который также выполняет некоторый код каждый раз, когда вы вызываете функцию. Это то, что вы делаете, например, когда используете декораторы для обеспечения безопасности потоков.
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" )
Что выводит это:
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