嵌套函数中的非局部变量
在了解闭包是什么之前,我们必须首先了解嵌套函数和非局部变量是什么。
在另一个函数中定义的函数称为嵌套函数。嵌套函数可以访问封闭作用域的变量。
在 Python 中,这些非局部变量默认是只读的,我们必须将它们显式声明为非局部变量(使用nonlocal 关键字)才能修改它们。
以下是访问非局部变量的嵌套函数的示例。
def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg(“Hello”)
输出
你好
我们可以看到嵌套printer()函数能够访问非本地留言 封闭函数的变量。
定义闭包函数
在上面的例子中,如果函数的最后一行print_msg()返回printer()函数而不是调用它会发生什么?这意味着函数定义如下:
def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let’s try calling this function. # Output: Hello another = print_msg(“Hello”) another()
输出
你好
这是不寻常的。
该print_msg()函数被调用带有字符串”Hello”和返回的函数被绑定到名字其他. 在调用 时another(),尽管我们已经完成了该print_msg()函数的执行,但仍然记得该消息。
这种将某些数据(”Hello在本例中)附加到代码的技术在 Python 中称为闭包。
即使变量超出范围或函数本身从当前命名空间中删除,封闭范围中的这个值也会被记住。
尝试在 Python shell 中运行以下命令以查看输出。
>>> del print_msg >>> another() Hello >>> print_msg(“Hello”) Traceback (most recent call last): … NameError: name ‘print_msg’ is not defined
在这里,即使原始函数被删除,返回的函数仍然有效。
我们什么时候关闭?
从上面的例子可以看出,当嵌套函数引用其封闭范围内的值时,我们在 Python 中有一个闭包。
在 Python 中创建闭包必须满足的条件总结为以下几点。
- 我们必须有一个嵌套函数(函数内的函数)。
- 嵌套函数必须引用在封闭函数中定义的值。
- 封闭函数必须返回嵌套函数。
什么时候使用闭包?
那么闭包有什么用呢?
闭包可以避免使用全局值并提供某种形式的数据隐藏。它还可以为该问题提供面向对象的解决方案。
当在一个类中实现的方法很少(大多数情况下是一种方法)时,闭包可以提供一种替代的更优雅的解决方案。但是当属性和方法的数量越来越多时,最好实现一个类。
这是一个简单的示例,其中闭包可能比定义类和创建对象更可取。但偏好是你的。
def makemultiplierof(n): def multiplier(x): return x n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))
*输出
27 15 30
Python 装饰器也广泛使用了闭包。
最后,最好指出封闭函数中包含的值是可以找到的。
如果函数对象closure是闭包函数,则所有函数对象都有一个属性,该属性返回单元对象的元组。参考上面的例子,我们知道times3并且times5是闭包函数。
>>> makemultiplierof.closure >>> times3.closure (
单元格对象具有存储关闭值的属性 cell_contents。
>>> times3.__closure