views:

1011

answers:

7

I've been reading a lot about closures and I think I understand them, but without clouding the picture for myself and others, I was wondering if anyone can explain closures as succinctly and clearly as possible to me and others? I'm looking for a simple explanation that might help me wrap my head around why I should be using them in certain instances.

+21  A: 

It's simple: A function that references variables from a containing scope, potentially after flow-of-control has left that scope. That last bit is very useful:

>>> def makeConstantAdder(x):
...     constant = x
...     def adder(y):
...         return y + constant
...     return adder
... 
>>> f = makeConstantAdder(12)
>>> f(3)
15
>>> g = makeConstantAdder(4)
>>> g(3)
7

Note that 12 and 4 have "disappeared" inside f and g, respectively, this feature is what make f and g proper closures.

Anders Eurenius
+3  A: 

I've never heard of transactions being used in the same context as explaining what a closure is and there really aren't any transaction semantics here.

It's called a closure because it "closes over" the outside variable (constant)--i.e., it's not just a function but an enclosure of the environment where the function was created.

In the following example, calling the closure g after changing x will also change the value of x within g, since g closes over x:

x = 0

def f():
  def g(): 
    x * 2
  return g


closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4
Mark Cidade
You have syntax error in the code; it should be `def f():`
muhuk
+5  A: 

I like this rough, succinct definition:

A function that can refer to environments that are no longer active.

I'd add

A closure allows you to bind variables into a function without passing them as parameters.

Decorators which accept parameters are a common use for closures. Closures are a common implementation mechanism for that sort of "function factory". I frequently choose to use closures in the Strategy Pattern when the strategy is modified by data at run-time.

In a language that allows anonymous block definition -- e.g., Ruby, C# -- closures can be used to implement (what amount to) novel new control structures. The lack of anonymous blocks is among the limitations of closures in Python.

ESV
+4  A: 

To be honest, I understand closures perfectly well except I've never been clear about what exactly is the thing which is the "closure" and what's so "closure" about it. I recommend you give up looking for any logic behind the choice of term.

Anyway, here's my explanation:

def foo():
   x = 3
   def bar():
      print x
   x = 5
   return bar

bar = foo()
bar()   # print 5

A key idea here is that the function object returned from foo retains a hook to the local var 'x' even though 'x' has gone out of scope and should be defunct. This hook is to the var itself, not just the value that var had at the time, so when bar is called, it prints 5, not 3.

Also be clear that Python 2.x has limited closure: there's no way I can modify 'x' inside 'bar' because writing 'x = bla' would declare a local 'x' in bar, not assign to 'x' of foo. This is a side-effect of Python's assignment=declaration. To get around this, Python 3.0 introduces the nonlocal keyword:

def foo():
   x = 3
   def bar():
      print x
   def ack():
      nonlocal x
      x = 7
   x = 5
   return (bar, ack)

bar, ack = foo()
ack()   # modify x of the call to foo
bar()   # print 7
Jegschemesch
A: 

The best explanation I ever saw of a closure was to explain the mechanism. It went something like this:

Imagine your program stack as a degenerate tree where each node has only one child and the single leaf node is the context of your currently executing procedure.

Now relax the constraint that each node can have only one child.

If you do this, you can have a construct ('yield') that can return from a procedure without discarding the local context (i.e. it doesn't pop it off the stack when you return). The next time the procedure is invoked, the invocation picks up the old stack (tree) frame and continues executing where it left off.

ConcernedOfTunbridgeWells
That's NOT an explanation of closures.
Jules
You're describing continuations, not closures.
Matt Olenik
+6  A: 

Closure on closures

Objects are data with methods attached, closures are functions with data attached.

def make_counter():
    i = 0
    def counter(): # counter() is a closure
        nonlocal i
        i += 1
        return i
    return counter

c1 = make_counter()
c2 = make_counter()

print (c1(), c1(), c2(), c2())
# -> 1 2 1 2
J.F. Sebastian
Thanks J.F. this was the clearest.
knowncitizen
+1  A: 

Here's a typical use case for closures - callbacks for GUI elements (this would be an alternative to subclassing the button class). For example, you can construct a function that will be called in response to a button press, and "close" over the relevant variables in the parent scope that are necessary for processing the click. This way you can wire up pretty complicated interfaces from the same initialization function, building all the dependencies into the closure.