Decorator Dissection

Ron_Adam radam2 at tampabay.rr.com
Sat Apr 2 15:34:21 EST 2005


On Sat, 02 Apr 2005 21:04:57 +0200, "Diez B. Roggisch"
<deetsNOSPAM at web.de> wrote:

>> I followed that part.  The part that I'm having problems with is the
>> first nested function get's the argument for the function name without
>> a previous reference to the argument name in the outer frames. So, a
>> function call to it is being made with the function name as the
>> argument, and that isn't visable so it looks as if it's magic.
>
>No, its not - but I stepped into that trap before - and thought its magic :)

It's magic until we understand it. ;)

I get the feeling that those who have gotten to know decorators find
them easy, and those who haven't, find them nearly impossible to
understand.  Which means there is a fairly large first few steps to
get over, then it gets easy.  There *is* some underlying processes
being made, which is also the reason that makes them attractive. Less
type/declare/organize/etc...  but that is also what causes the
difficulty in understanding and using them at first.  

>The trick is to know that
>
> - a decorator is a callable
> - get passed a callable
> - has to return a callable
>
>So this is the simplest decorator imaginable is:
>
>def identity(f):
>    return f
>
>And the decorator _syntax_ is just a python expression that has to be
>_evaluated_ to a yield decorator. So
>
>@identity
>def foo(self):
>    pass

This much I understand. 

>the @identity is just the expression evaluated - to the function reference
>to identity, which is callable and follows the decorator protocol - and the
>_result_ of that evaluation is called with the callable in question.

This tells me what it is, and what it does, but not how it works.  How
is the ***expression evaluated***,  what is the ***decorator
protocol***.

Those are the parts I'm trying to understand at this point.  I know
this is the equivalent of looking behind the curtains to reveal the
little man who is the wizard.  But I can't resist. :)

>So if you want to have _parametrized_ decorators, that expression is
>_evaluated_ and has to yield a decorator. Like this:
>

There's that word again... **evaluated**.  How?

>def arg_decorator(arg):
>    def real_decorator(f):
>        return f
>    return real_decorator
>
>So, this works 
>
>@arg_decorator('fooobar')
>def foo(self):
>    pass
>
>@arg_decorator('fooobar') is evaluated to real_decorator (which a scope
>containing arg), and _that_ gets called with foo.
>

So if I'm following you right?

When the interpreter gets to the line @arge_decorator('fooobar')

it does the following?

foo = arg_decorator('fooobar')(foo)() #?      

(experiment with idle a bit...)

Ok I got it. :)

I wasn't aware that the form:

	result = function(args)(args)

Was a legal python statement.

So python has a built in mechanism for passing multiple argument sets
to nested defined functions! (click)  Which means this is a decorator
without the decorator syntax.

def arg_decorator(arg1):
    def real_decorator(function):
		def wrapper(arg2)
        return f(arg2)
    return real_decorator

def foo(arg2):
    pass
foo = arg_decorator('fooobar')(foo)(2arg)

The apparent magic is the silent passing of the second two arguments.

So this isn't a decorator question any more.  Each argument gets
passed to the next inner defined function,  via... a stack(?)  ;)

Somehow I think I've completed a circle.  LOL

Cheers,
Ron


>HTH - bit me the first time too :)




More information about the Python-list mailing list