Interesting decorator use.
Steven Bethard
steven.bethard at gmail.com
Thu Feb 24 17:00:46 EST 2005
Tom Willis wrote:
> Question on decorators in general. Can you parameterize those?
>
> If I wanted to something and after the function call for example, I
> would expect something like this would work.
>
> def prepostdecorator(function,pre,post):
> def wrapper(*args,**kwargs):
> pre()
> result = function(*args,**kwargs)
> post()
> return result
> return wrapper
>
> def dopre():
> print "call pre"
>
> def dopost():
> print "call post"
>
> @prepostdecorator(pre,post)
> def sayhello(Name):
> print "Hey %s, nice to meet you" % Name
>
> #sayhello = prepostdecorator(sayhello,dopre,dopost)
>
> if __name__=="__main__":
> sayhello("Dude")
>
> but I get ...
> TypeError: prepostdecorator() takes exactly 3 arguments (2 given)
You get this TypeError for the same reason that I get the following
TypeError:
py> def prepostdecorator(function, pre, post):
... pass
...
py> prepostdecorator(1, 2)
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: prepostdecorator() takes exactly 3 arguments (2 given)
The expression after @ is a _normal Python expression_. So since you
couldn't call prepostdecorator with 2 arguments in any other situation,
you still can't.
If you want to call prepostdecorator with 2 arguments, you need to write
it this way. A few options:
(1) Use nested functions:
py> def prepostdecorator(pre,post):
... def decorator(function):
... def wrapper(*args,**kwargs):
... pre()
... result = function(*args,**kwargs)
... post()
... return result
... return wrapper
... return decorator
...
py> @prepostdecorator(dopre, dopost)
... def sayhello(name):
... print "Hey %s, nice to meet you" % name
...
py> sayhello('Tom')
call pre
Hey Tom, nice to meet you
call post
(2) Use functional.partial (PEP 309[1])
py> def prepostdecorator(pre, post, function):
... def wrapper(*args,**kwargs):
... pre()
... result = function(*args,**kwargs)
... post()
... return result
... return wrapper
...
py> @partial(prepostdecorator, dopre, dopost)
... def sayhello(name):
... print "Hey %s, nice to meet you" % name
...
py> sayhello('Tom')
call pre
Hey Tom, nice to meet you
call post
(3) Use a class:
py> class prepostdecorator(object):
... def __init__(self, pre, post):
... self.pre, self.post = pre, post
... def __call__(self, function):
... def wrapper(*args,**kwargs):
... self.pre()
... result = self.function(*args,**kwargs)
... self.post()
... return result
... return wrapper
py> @prepostdecorator(dopre, dopost)
... def sayhello(name):
... print "Hey %s, nice to meet you" % name
...
py> sayhello('Tom')
call pre
Hey Tom, nice to meet you
call post
Note that in all of the above cases, the result of evaluating the
expression after the @ is a callable object that takes _exactly one_
argument, the function to be decorated.
HTH,
STeVe
[1] http://www.python.org/peps/pep-0309.html
More information about the Python-list
mailing list