[Baypiggies] JJ's decorators

Shannon -jj Behrens jjinux at gmail.com
Fri Mar 6 07:19:12 CET 2009


On Thu, Mar 5, 2009 at 7:06 AM, Aahz <aahz at pythoncraft.com> wrote:
> 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.

Thanks, Aahz.

-jj

--
In this life we cannot do great things. We can only do small things
with great love. -- Mother Teresa
http://jjinux.blogspot.com/


More information about the Baypiggies mailing list