你能解释一下闭包吗(因为它们与 Python 相关)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13857/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:23:48  来源:igfitidea点击:

Can you explain closures (as they relate to Python)?

pythonfunctional-programmingclosures

提问by knowncitizen

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.

我已经阅读了很多关于闭包的内容,我想我理解它们,但不要为我自己和其他人蒙上阴影,我希望有人能够尽可能简洁明了地解释闭包。我正在寻找一个简单的解释,可以帮助我了解我想在哪里以及为什么要使用它们。

回答by jfs

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

回答by Anders Eurenius

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.

请注意,12 和 4 分别在 f 和 g 内部“消失”了,这个特性是使 f 和 g 正确闭包的原因。

回答by ESV

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 Patternwhen 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.

在允许匿名块定义的语言中——例如,Ruby、C#——闭包可用于实现(相当于)新颖的新控制结构。缺少匿名块是Python 中闭包的局限性之一

回答by Jegschemesch

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.

这里的一个关键思想是,从 foo 返回的函数对象保留了一个到本地 var 'x' 的钩子,即使 'x' 已经超出范围并且应该已经失效。这个钩子是针对 var 本身的,而不仅仅是 var 当时的值,所以当 bar 被调用时,它会打印 5,而不是 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:

还要清楚 Python 2.x 的闭包有限:我无法修改 'bar' 中的 'x',因为写 'x = bla' 会在 bar 中声明一个本地 'x',而不是分配给 foo 的 'x' .这是 Python 的 assignment=declaration 的副作用。为了解决这个问题,Python 3.0 引入了 nonlocal 关键字:

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

回答by Mark Cidade

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 之后调用闭包 g 也会改变 g 中 x 的值,因为 g 关闭了 x:

x = 0

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


closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4

回答by Mark Cidade

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.

这是闭包的典型用例 - GUI 元素的回调(这将是对按钮类进行子类化的替代方法)。例如,您可以构造一个函数,该函数将在按钮按下时被调用,并“关闭”父作用域中处理点击所需的相关变量。通过这种方式,您可以从同一个初始化函数连接非常复杂的接口,将所有依赖项构建到闭包中。

回答by Aaron Hall

In Python, a closure is an instance of a function that has variables bound to it immutably.

在 Python 中,闭包是一个函数的实例,它具有不可改变的绑定到它的变量。

In fact, the data model explains thisin its description of functions' __closure__attribute:

事实上,数据模型在其对函数__closure__属性的描述中解释了这一点

None or a tuple of cellsthat contain bindings for the function's free variables. Read-only

None 或包含函数自由变量绑定的单元格元组。只读

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 baris.

显然,我们知道我们现在有一个从变量 name 指向的函数closure_instance。表面上,如果我们用一个对象调用它,bar,它应该打印字符串,'foo'无论 的字符串表示bar是什么。

In fact, the string 'foo' isbound to the instance of the function, and we can directly read it here, by accessing the cell_contentsattribute of the first (and only) cell in the tuple of the __closure__attribute:

事实上,字符串“富”关联到函数的实例,我们直接可以在这里阅读,通过访问cell_contents中的元组的第一个(也是唯一的)细胞的属性__closure__属性:

>>> closure_instance.__closure__[0].cell_contents
'foo'

As an aside, cell objects are described in the C API documentation:

顺便说一句,C API 文档中描述了单元格对象:

"Cell" objects are used to implement variables referenced by multiple scopes

“Cell”对象用于实现多个作用域引用的变量

And we can demonstrate our closure's usage, noting that 'foo'is stuck in the function and doesn't change:

我们可以演示我们的闭包的用法,注意它'foo'被困在函数中并且不会改变:

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

给出的例子使用闭包作为偏函数,但如果这是我们唯一的目标,同样的目标可以用 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.

还有更复杂的闭包不适合部分函数示例,如果时间允许,我将进一步演示它们。

回答by thiagoh

Here is an example of Python3 closures

这是 Python3 闭包的示例

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

回答by Dinesh Sonachalam

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

Closures 满足的标准是:

  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.
  1. 我们必须有嵌套函数。
  2. 嵌套函数必须引用在封闭函数中定义的值。
  3. 封闭函数必须返回嵌套函数。


# 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

回答by Nitish Chauhan

we all have used Decoratorsin python. They are nice examples to show what are closure functions in python.

我们都在 python 中使用过装饰器。它们是很好的例子来展示什么是 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

这里的最终值为 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.

在这里,包装器函数能够访问 func 对象,因为包装器是“词法闭包”,它可以访问它的父属性。这就是为什么它能够访问 func 对象。