closure = decorator?

Jussi Piitulainen jpiitula at ling.helsinki.fi
Fri Oct 11 08:01:40 EDT 2013


Steven D'Aprano writes:
> On Fri, 11 Oct 2013 10:14:29 +0300, Jussi Piitulainen wrote:
> > Roy Smith writes:
> >> In article <m2a9ihxf3a.fsf at cochabamba.vanoostrum.org>,
> >>  Piet van Oostrum wrote:
> >> 
> >> > I usually say that a closure is a package, containing a
> >> > function with some additional data it needs. The data usually
> >> > is in the form of name bindings.
> >> 
> >> That's pretty close to the way I think about it.  The way it was
> >> originally described to me is, "A closure is a function bundled
> >> up with it's arguments".
> > 
> > Really? It should be more like "a function bundled up with some
> > other function's arguments" and even more like "a function bundled
> > up with bindings for its free variables".
> 
> Closures have nothing to do with *arguments*. A better definition of
> a closure is that it is a function together with a snapshot of the
> environment it was called from.

Well, first, I was only trying to see something good in Piet's and
Roy's formulations.

Second, it's precisely not (a snapshot of) the environment where the
function is *called* from, it's (a snapshot of) the environment where
the function was *created* in. This is the whole *point*.

Third, to be even more pedantic, in the context where I think closures
originally appeared as an innovation, all local variables are bound by
a lambda. There the (non-global) free variables of a function *are*
arguments of *another* function. I can expand on this if you like, but
it will be in terms of another language, and not terribly relevant to
this discussion anyway.

> def func(arg):
>     y = arg + 1
>     def inner():
>         return y + 1000
>     return inner
> 
> f = func(1)
> 
> At this point, f is a closure. It needs to know the value of y (not
> the argument to func) in order to work, and the implementation is to
> store that information inside f.func_closure (or f.__closure__ in
> Python 3).  The part of the calling environment which is saved is y:
> 
> py> f.func_closure[0].cell_contents
> 2

Whether there is a y in the *calling* environment or not is
*irrelevant*.

   >>> (lambda y : func(1))('whatever')()
   1002

> > And the data that makes a function a closure is bindings always,
> > by definition, not just usually.
> 
> Its not just *any* bindings though, it is specifically bindings to
> variables in the environment from which it was called.

In the environment where it was created.

> [...]
> >> That's a closure.
> > 
> > I fail to see a closure here. I see a class. I see an implied
> > object that could as well be dict(spot=37, time=5). Other entities
> > (garage and attendants) are not made sufficiently explicit.
> 
> In general, anything you can do with a closure, you can do with an
> object explicitly recording whatever state you want. A closure is
> just one implementation of "callable object with state that can be
> set when you create it". The closure f defined above could instead
> be written as:
> 
> class Func:
>     def __init__(self, arg):
>         self.y = arg + 1
>     def __call__(self):
>         return self.y + 1000
> 
> f = Func(1)
> 
> Which is better? If you want to expose the value of y to the outside
> world to modify, the class solution is better. If you don't, the
> closure is better. Closures tend to be more compact, and I suspect
> more efficient, but there's nothing you can do with one you can't do
> with the other.

Sure.



More information about the Python-list mailing list