Steven D'Aprano writes: > On Fri, 11 Oct 2013 10:14:29 +0300, Jussi Piitulainen wrote: > > Roy Smith writes: > >> In article <m2a9ihxf3a....@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. -- https://mail.python.org/mailman/listinfo/python-list