decorator peculiarity
Scott David Daniels
Scott.Daniels at Acm.Org
Fri Dec 17 10:16:21 EST 2004
Diez B. Roggisch wrote:
> def decorate(func):
> def _d(*args, **kwargs):
> do_something()
> # call func
> func(*args, **kwargs)
> return _d
> @decorate
> def foo():
> pass
> [T]he function decorator has to return a function that is bound to the name
> foo in the originating context (module or class) and gets the function
> passed as argument. If I want my decorator ... parametrized...:
> @decorate(arg)
> def foo():
> pass
> def decorate(arg):
> def f(func):
> def _d(*args, **kwargs):
> do_something(arg)
> # call func
> func(*args, **kwargs)
> return _d
> Now why this layer of indirection?
Let's rewrite your example a bit, it may become obvious.
def decorate(func):
def replacement(argspec):
do_something()
return func(argspec)
return replacement
@decorate
def foo(argspec): pass
---
def decorate2():
def _decorate(func):
def replacement(argspec):
do_something()
return func(argspec)
return replacement
return _decorate
@decorate()
def foo(argspec): pass
---
def decorate3(arg):
def _decorate(func):
def replacement(argspec):
do_something()
return func(argspec)
return replacement
return _decorate
@decorate3(arg)
def foo(argspec): pass
---
Clear now? there is no extra indirection. If you call something on
the @ line, the _result_of_that_call_ should be a decorator function.
If you use my curry recipe in the python cookbook, you can use curry
lower the apparent "indirection":
def decorate4(arg, func):
def replacement(argspec):
do_something()
return func(argspec)
return replacement
@curry(decorate4, arg)
def foo(argspec): pass
By the way, I _do_ think curry is an appropriate name. The Curry-Howard
isomorphism shows the equivalence of a functions on tuples with single-
argument functions returning functions. In a functional language, where
there is no distinction made between a a function with no arg and its
result, the transformation is clear. With a language like Python, which
pays attention to when a function is invoked, you are better off
returning a function which can take the remaining arguments, and
controlling when the final function is called by returning a function
that can take all the remaining arguments at once.
-Scott David Daniels
Scott.Daniels at Acm.Org
More information about the Python-list
mailing list