decorator peculiarity

Fredrik Lundh fredrik at pythonware.com
Sun Dec 19 11:31:42 EST 2004


Diez B. Roggisch wrote:

> 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.

the decorator itself must be a callable, so to create parameterized decorators,
you have to create a callable that returns a callable.

due to some weird obsession with nested functions and lexical scoping, most
decorator examples use functions inside functions inside functions, but you can
of course use a good old class instead:

    class decorator:
    def __init__(self, params):
        # save the parameters
    def __call__(self, func):
        # decorate the function
        return func

    @decorator(params)
    def func(...):
        pass

or even:

class decorator:
    def __init__(self, params):
        # save the parameters
    def __call__(self, func):
        self.func = func
        return self.handler
    def handler(self, *args):
        # do something
        self.func(*args)
        # do something

</F> 






More information about the Python-list mailing list