Can you explain closures (as they relate to Python

2019-01-01 12:05发布

问题:

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.

回答1:

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


回答2:

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.



回答3:

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.



回答4:

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


回答5:

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


回答6:

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.



回答7:

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

Partial Functions

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.



回答8:

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


回答9:

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.



回答10:

# 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:

  1. We must have nested function.
  2. Nested function must refer to the value defined in the enclosing function.
  3. Enclosing function must return the nested function.

# 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


回答11:

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.



回答12:

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.



回答13:

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.