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 -- http://mail.python.org/mailman/listinfo/python-list