Reputation: 1603
I've been reading a lot about closures and I think I understand them, but without clouding the picture for myself and others, I am hoping someone can explain closures as succinctly and clearly as possible. I'm looking for a simple explanation that might help me understand where and why I would want to use them.
Upvotes: 109
Views: 25827
Reputation: 141
This is my recent LinkedIn post about closure. Hope it will help along with the image.
Post link: closure in Python
Sometimes,
How does that even work?
Enter ๐ฐ๐น๐ผ๐๐๐ฟ๐ฒ๐!
Let's take a look at the image below,
1๏ธโฃ When ๐ฝ๐ฎ๐ฟ๐ฒ๐ป๐_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป is called:
๐ Wait, ๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป isnโt called yet!
2๏ธโฃ When ๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป is called:
๐ Wait, when did we call ๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป?
๐ค Remember we stored ๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป as an object in the ๐ฐ๐น๐ผ๐๐๐ฟ๐ฒ variable?
So, when we call closure(5), it is essentially a call as if calling ๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป(5)! ๐
Now, Let's move on ...
๐ฝ๐ฎ๐ฟ๐ฒ๐ป๐_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป is removed from the stack
x is still in memory ---> can be accessed by our ๐ฐ๐น๐ผ๐๐๐ฟ๐ฒ variable?
๐ฐ๐ต๐ถ๐น๐ฑ_๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป is pushed to the stack
it defines a variable ๐ and assigns a value (๐ = 5)
it looks for ๐ , but ๐ is not in its lexical scope
it looks for outer lexical scope and finds x with the help of the closure variable.
๐ Takeaway
๐ TL;DR:
Closures = A function + its saved context.
You can think of them as --> ๐ณ๐๐ป๐ฐ๐๐ถ๐ผ๐ป๐ ๐๐ถ๐๐ต ๐บ๐ฒ๐บ๐ผ๐ฟ๐.
Upvotes: -1
Reputation: 11574
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
Upvotes: 24
Reputation: 43
A closure in Python refers to a function that retains access to variables from the outer (enclosing) scope even after the outer function has finished executing. In simpler terms, a closure "closes over" or captures the variables it needs from its surrounding environment, allowing you to maintain state information in a way that's both elegant and efficient.
Example:
def multiplier(factor):
def multiply(x):
return x * factor
return multiply
# Usage
double = multiplier(2)
triple = multiplier(3)
print(double(5)) # Output: 10
print(triple(5)) # Output: 15
Upvotes: 1
Reputation: 7730
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.
Upvotes: 16
Reputation: 11
I would like to share my example and an explanation about closures. I made a python example, and two figures to demonstrate stack states.
def maker(a, b, n):
margin_top = 2
padding = 4
def message(msg):
print('\nโ * margin_top, a * n,
' โ * padding, msg, ' โ * padding, b * n)
return message
f = maker('*', '#', 5)
g = maker('๏ง', 'โฅโ, 3)
โฆ
f('hello')
g(โgood bye!')
The output of this code would be as follows:
***** hello #####
๏ง๏ง๏ง good bye! โฅโฅโฅ
Here are two figures to show stacks and the closure attached to the function object.
when the function is returned from maker
when the function is called later
When the function is called through a parameter or a nonlocal variable, the code needs local variable bindings such as margin_top, padding as well as a, b, n. In order to ensure the function code to work, the stack frame of the maker function which was gone away long ago should be accessible, which is backed up in the closure we can find along with the 'message's function object.
Upvotes: 1
Reputation: 385
we all have used Decorators in python. They are nice examples to show what are closure functions in python.
class Test():
def decorator(func):
def wrapper(*args):
b = args[1] + 5
return func(b)
return wrapper
@decorator
def foo(val):
print val + 2
obj = Test()
obj.foo(5)
here final value is 12
Here, the wrapper function is able to access func object because wrapper is "lexical closure", it can access it's parent attributes. That is why, it is able to access func object.
Upvotes: 1
Reputation: 1369
# A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.
# Defining a closure
# This is an outer function.
def outer_function(message):
# This is an inner nested function.
def inner_function():
print(message)
return inner_function
# Now lets call the outer function and return value bound to name 'temp'
temp = outer_function("Hello")
# On calling temp, 'message' will be still be remembered although we had finished executing outer_function()
temp()
# Technique by which some data('message') that remembers values in enclosing scopes
# even if they are not present in memory is called closures
# Output: Hello
Criteria to met by Closures are:
# Example 2
def make_multiplier_of(n): # Outer function
def multiplier(x): # Inner nested function
return x * n
return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
print(times5(3)) # 15
print(times3(2)) # 6
Upvotes: 6
Reputation: 99957
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():
return x * 2
return g
closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4
Upvotes: 8
Reputation: 7388
Here is an example of Python3 closures
def closure(x):
def counter():
nonlocal x
x += 1
return x
return counter;
counter1 = closure(100);
counter2 = closure(200);
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))
# result
i from closure 1 101
i from closure 1 102
i from closure 2 201
i from closure 1 103
i from closure 1 104
i from closure 1 105
i from closure 2 202
Upvotes: 1
Reputation: 394965
In Python, a closure is an instance of a function that has variables bound to it immutably.
In fact, the data model explains this in its description of functions' __closure__
attribute:
None or a tuple of cells that contain bindings for the functionโs free variables. Read-only
To demonstrate this:
def enclosure(foo):
def closure(bar):
print(foo, bar)
return closure
closure_instance = enclosure('foo')
Clearly, we know that we now have a function pointed at from the variable name closure_instance
. Ostensibly, if we call it with an object, bar
, it should print the string, 'foo'
and whatever the string representation of bar
is.
In fact, the string 'foo' is bound to the instance of the function, and we can directly read it here, by accessing the cell_contents
attribute of the first (and only) cell in the tuple of the __closure__
attribute:
>>> closure_instance.__closure__[0].cell_contents
'foo'
As an aside, cell objects are described in the C API documentation:
"Cell" objects are used to implement variables referenced by multiple scopes
And we can demonstrate our closure's usage, noting that 'foo'
is stuck in the function and doesn't change:
>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux
And nothing can change it:
>>> closure_instance.__closure__ = None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
The example given uses the closure as a partial function, but if this is our only goal, the same goal can be accomplished with functools.partial
>>> from __future__ import print_function # use this if you're in Python 2.
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux
There are more complicated closures as well that would not fit the partial function example, and I'll demonstrate them further as time allows.
Upvotes: 5
Reputation: 1
For me, "closures" are functions which are capable to remember the environment they were created. This functionality, allows you to use variables or methods within the closure wich, in other way,you wouldn't be able to use either because they don't exist anymore or they are out of reach due to scope. Let's look at this code in ruby:
def makefunction (x)
def multiply (a,b)
puts a*b
end
return lambda {|n| multiply(n,x)} # => returning a closure
end
func = makefunction(2) # => we capture the closure
func.call(6) # => Result equal "12"
it works even when both, "multiply" method and "x" variable,not longer exist. All because the closure capability to remember.
Upvotes: 0
Reputation:
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.
Upvotes: 3
Reputation: 414199
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
Upvotes: 126
Reputation: 66612
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.
Upvotes: -2
Reputation: 4226
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.
Upvotes: 51