Python decorators ii:decorator Arguments
October, 2008
(This is the second part of the chapter excerpt from the Python 3 Patterns & Idioms (Python3 mode and usage), click here to read the first part)
review: Non-parameter-free Decorators
In the previous article, I described how to use decorators without parameters and use a class to implement it. Because I find it easier to accept.
If a parameterless decorator is created, the decorated function is passed to the constructor, and the __call__ () method is invoked each time the decorated function is invoked:
Class Decoratorwithoutarguments (object):
def __init__ (self, f):
"""
If There are no decorator arguments, the function
To being decorated is passed to the constructor.
"""
Print "Inside __init__ ()"
SELF.F = f
def __call__ (self, *args):
"""
The __call__ method isn't called until the
Decorated function is called.
"""
Print "Inside __call__ ()"
SELF.F (*args)
Print "After Self.f (*args)"
@decoratorWithoutArguments
Def sayhello (A1, A2, A3, A4):
print ' SayHello arguments: ', A1, A2, A3, A4
print "After decoration"
Print "Preparing to call SayHello ()"
SayHello ("Say", "hello", "argument", "list")
Print "After the SayHello () call"
SayHello ("A", "different", "set of", "arguments")
Print "after second SayHello ()"
All parameters of the decorated function are passed to __call__ (). The output results are:
Inside __init__ ()
After decoration
Preparing to call SayHello ()
Inside __call__ ()
SayHello Arguments:say Hello argument list
After Self.f (*args)
After the SayHello () call
Inside __call__ ()
SayHello arguments:a different set of arguments
After Self.f (*args)
After second SayHello ()
Note that __init__ () is the only method that is called to execute decoration, and __call__ () is invoked each time the SayHello () of the decorated is invoked.
containing parameters. Decorators
Now let's modify the code above to see what the result is when you add the parameters to the decorator.
Class Decoratorwitharguments (object):
def __init__ (self, arg1, arg2, ARG3):
"""
If There are decorator arguments, the function
To was decorated is isn't passed to the constructor!
"""
Print "Inside __init__ ()"
SELF.ARG1 = Arg1
SELF.ARG2 = arg2
SELF.ARG3 = Arg3
def __call__ (self, f):
"""
If There are decorator arguments, __call__ () is only called
Once, as part of the decoration process! can only give
It a single argument and which is the function object.
"""
Print "Inside __call__ ()"
def wrapped_f (*args):
Print "Inside wrapped_f ()"
Print "Decorator arguments:", Self.arg1, Self.arg2, SELF.ARG3
F (*args)
Print "After F (*args)"
Return Wrapped_f
@decoratorWithArguments ("Hello", "World", 42)
Def sayhello (A1, A2, A3, A4):
print ' SayHello arguments: ', A1, A2, A3, A4
print "After decoration"
Print "Preparing to call SayHello ()"
SayHello ("Say", "hello", "argument", "list")
Print "After the SayHello () call"
SayHello ("A", "different", "set of", "arguments")
Print "after second SayHello ()"
As you can see from the output, adding parameters causes a great change in program execution.
Inside __init__ ()
Inside __call__ ()
After decoration
Preparing to call SayHello ()
Inside Wrapped_f ()
Decorator Arguments:hello World 42
SayHello Arguments:say Hello argument list
After F (*args)
After the SayHello () call
Inside Wrapped_f ()
Decorator Arguments:hello World 42
SayHello arguments:a different set of arguments
After F (*args)
After second SayHello ()
Now the decoration method calls the constructor, and then immediately calls __call__ (), which can only contain one parameter (the function object) and return the decorated function object that replaces the original function. Note that __call__ () is invoked only once during the current decoration period, and the decorated function returned from __call__ () can then be used in the actual call.
Although this mechanism has some rationality-the constructor can get the decorator parameter here, but the __call__ () object can no longer be used as the decorated function. So you have to use __call__ () to perform decoration-you might be surprised to see this in a very different way for the first time, not to mention that you have to write and decorator complete different code.
containing Decorator parameters of Decorator function
Finally, let's look at a more complex decorator function implementation that requires you to handle all the details:
def decoratorfunctionwitharguments (Arg1, Arg2, ARG3):
Def wrap (f):