[Baypiggies] JJ's decorators

Aahz aahz at pythoncraft.com
Thu Mar 5 16:06:18 CET 2009


On Thu, Mar 05, 2009, Smith1, Robert E wrote:
>
> I put some print statements into your code to try and understand
> it. It appears that the logged "decorator function" gets executed
> during import/load, which also causes either pre_logged(f) or
> post_logged(f) to get executed. This statement appears to be the one
> that invokes pre_logged(f) or post_logged(f) (or at least it occurs
> right before):
>
> return {"pre": pre_logged, "post": post_logged}[when]
> 
> Is that correct - that invokes one of those two functions? And if so,
> how does "return pre_logged" invoke "pre_logged(f)"? 

It doesn't.  The problem is that there are really two different kinds of
decorators, those without arguments and those that take an argument.
Unfortunately, the second kind is more complicated, and therefore JJ's
example really isn't that simple.  Here's a hyper simplified tracing
decorator:

from functools import wraps

def tracer(f):
    @wraps(f)
    def t(*args, **kwargs):
        print f.func_name, args, kwargs
        return f(*args, **kwargs)
    return t

@tracer
def foo(x):
    print x

> Also, why is "f" explicitly declared as a parameter for "log",
> "pre_logged", and "post_logged", but not "logged"?

Because the first three are the actual wrappers, called during the
execution of f, but ``logged`` is the decorator.  In the simplified
case, you get f for free when calling t() because you can rely on Python
lexical closures passing f when tracer() is called the first time to
decorate foo.  However, when a decorator takes arguments, the wrappers
need to include f in their signatures.

Basically, to *write* decorators, you *REALLY* need to understand
closures and passing functions around as first-class objects or you won't
get anywhere.  On the other hand, as Charles was at pains to point out,
when you're just using someone else's decorators, you only need to
follow their instructions: notice how calling foo() is exactly the same
regardless of whether you use the @tracer line.
-- 
Aahz (aahz at pythoncraft.com)           <*>         http://www.pythoncraft.com/

"All problems in computer science can be solved by another level of     
indirection."  --Butler Lampson


More information about the Baypiggies mailing list