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

kno*_*zen 78 python closures functional-programming

我一直在阅读很多关于闭包的内容,我认为我理解它们,但是没有为自己和他人蒙上阴影,我希望有人可以尽可能简洁明了地解释闭包.我正在寻找一个简单的解释,可以帮助我理解我想要使用它们的地点和原因.

jfs*_*jfs 88

封闭关闭

对象是附加方法的数据,闭包是附加数据的函数.

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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,在python 3中添加了`nonlocal`,python 2.x没有全开,读写闭包(即你可以读取封闭的变量,但不能更改它们的值) (6认同)
  • @JamesPorter:注意:您可以通过使用可变对象来模拟Python 2中的`nonlocal`关键字,例如,`L = [0] \n def counter():L [0] + = 1; 返回L [0]`即,在这种情况下,您不能更改名称(将其绑定到另一个对象)*但是*您可以更改名称所指的可变对象本身.该列表是必需的,因为整数在Python中是不可变的. (6认同)

And*_*ius 44

它很简单:一个函数引用包含范围的变量,可能在控制流离开该范围之后.最后一点非常有用:

>>> 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
Run Code Online (Sandbox Code Playgroud)

注意12和4分别在f和g内部"消失",这个特征使得f和g适当地闭合.

  • 无需执行“constant = x”;你可以在嵌套函数中执行“return y + x”(或者接收名称为“constant”的参数),它就可以正常工作;闭包捕获参数与非参数局部变量没有什么不同。 (4认同)

ESV*_*ESV 14

我喜欢这个粗略,简洁的定义:

可以引用不再活动的环境的函数.

我补充一下

闭包允许您将变量绑定到函数中,而不将它们作为参数传递.

接受参数的装饰器是闭包的常用用途.闭包是这种"功能工厂"的常见实现机制.在运行时通过数据修改策略时,我经常选择在策略模式中使用闭包.

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


Jeg*_*sch 14

说实话,我完全理解闭包,除了我从来都不清楚究竟什么是"闭合"以及什么是"关闭"它.我建议你放弃寻找术语选择背后的任何逻辑.

无论如何,这是我的解释:

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

bar = foo()
bar()   # print 5
Run Code Online (Sandbox Code Playgroud)

这里的一个关键想法是,从foo返回的函数对象保留了一个钩子到局部变量'x',即使'x'已经超出范围并且应该不存在.这个钩子是var本身,而不仅仅是var当时的值,所以当调用bar时,它会打印5而不是3.

另外要明确Python 2.x的封闭性有限:我无法修改'bar'中的'x',因为写'x = bla'会在bar中声明一个本地'x',而不是分配给foo的'x' .这是Python的赋值=声明的副作用.为了解决这个问题,Python 3.0引入了非本地关键字:

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
Run Code Online (Sandbox Code Playgroud)


Mar*_*ade 6

我从来没有听说过在同一个上下文中使用事务来解释闭包是什么,这里确实没有任何事务语义.

它被称为闭包,因为它"关闭"外部变量(常量) - 即,它不仅仅是一个函数,而是创建函数的环境的封闭.

在下面的示例中,在更改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
Run Code Online (Sandbox Code Playgroud)


Din*_*lam 6

# 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
Run Code Online (Sandbox Code Playgroud)

闭包要满足的标准是:

  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
Run Code Online (Sandbox Code Playgroud)