D
Diez B. Roggisch
Hi,
I just wrote my first decorator example - and I already love them.
However I've encountered one peculiarity that strikes me odd:
When one writes a decorated function like this:
@decorate
def foo():
pass
the function decorate usually looks like this:
def decorate(func):
def _d(*args, **kwargs):
do_something()
# call func
func(*args, **kwargs)
return _d
So the 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.
But if I want my decorator to be parametrized, it looks like this:
@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
So what happens is that an decorater with arguments is called with these,
returns a callable that then is called with foo, and the result is stored
under foo.
Now why this layer of indirection? I would have supposed that things look
like this:
def decorate(func, arg):
def _d(*args, **kwargs):
do_something(arg)
# call func
func(*args, **kwargs)
return _d
A sideeffect of this behaviour is that for a fully keyword-argumentized
function I still have to write parentheses:
@decorate()
def foo():
pass
def decorate(arg=None):
def f(func):
def _d(*args, **kwargs):
do_something(arg)
# call func
func(*args, **kwargs)
return _d
I don't mind the extra parentheses too much - it just made me wonder what
the rationale behind this is.
I just wrote my first decorator example - and I already love them.
However I've encountered one peculiarity that strikes me odd:
When one writes a decorated function like this:
@decorate
def foo():
pass
the function decorate usually looks like this:
def decorate(func):
def _d(*args, **kwargs):
do_something()
# call func
func(*args, **kwargs)
return _d
So the 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.
But if I want my decorator to be parametrized, it looks like this:
@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
So what happens is that an decorater with arguments is called with these,
returns a callable that then is called with foo, and the result is stored
under foo.
Now why this layer of indirection? I would have supposed that things look
like this:
def decorate(func, arg):
def _d(*args, **kwargs):
do_something(arg)
# call func
func(*args, **kwargs)
return _d
A sideeffect of this behaviour is that for a fully keyword-argumentized
function I still have to write parentheses:
@decorate()
def foo():
pass
def decorate(arg=None):
def f(func):
def _d(*args, **kwargs):
do_something(arg)
# call func
func(*args, **kwargs)
return _d
I don't mind the extra parentheses too much - it just made me wonder what
the rationale behind this is.