🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Python 闭包 > 原文: [https://www.programiz.com/python-programming/closure](https://www.programiz.com/python-programming/closure) #### 在本教程中,您将了解 Python 闭包,如何定义闭包以及使用它的原因。 ## 嵌套函数中的非局部变量 在了解什么是闭包之前,我们必须首先了解什么是嵌套函数和非局部变量。 在另一个函数内部定义的函数称为嵌套函数。 嵌套函数可以访问定义范围的变量。 在 Python 中,默认情况下,这些非局部变量是只读的,我们必须将它们明确声明为非局部变量(使用[`nonlocal`关键字](/python-programming/keyword-list#nonlocal))才能进行修改。 以下是访问非局部变量的嵌套函数的示例。 ```py 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") ``` **输出** ```py Hello ``` 我们可以看到嵌套`printer()`函数能够访问外层函数的非本地`msg`变量。 * * * ## 定义闭包函数 在上面的示例中,如果函数`print_msg()`的最后一行返回了`printer()`函数而不是调用它,将会发生什么情况? 这意味着该函数的定义如下: ```py 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() ``` **输出**: ```py Hello ``` 这很不寻常。 用字符串`"Hello"`调用`print_msg()`函数,并将返回的函数绑定到名称`another`上。 调用`another()`时,尽管我们已经完成了`print_msg()`函数的执行,但仍会记住该消息。 这种将某些数据(在这种情况下为`"Hello`)附加到代码的技术在 Python 中称为**闭包**。 即使变量超出范围或函数本身已从当前名称空间中删除,也将记住定义范围中的该值。 尝试在 Python Shell 中运行以下命令以查看输出。 ```py >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last): ... NameError: name 'print_msg' is not defined ``` 在这里,即使删除原始函数,返回的函数仍然可以使用。 * * * ## 什么时候拥有闭包? 从上面的示例可以看出,当嵌套函数在其定义范围内引用一个值时,在 Python 中会有一个闭包。 以下几点总结了在 Python 中创建闭包必须满足的条件。 * 我们必须有一个嵌套函数(函数在函数内部)。 * 嵌套函数必须引用在外层函数中定义的值。 * 外层函数必须返回嵌套函数。 * * * ## 什么时候使用闭包? 那么,闭包有什么好处呢? 闭包可以避免使用全局值,并提供某种形式的数据隐藏。 它还可以为该问题提供面向对象的解决方案。 当在一个类中实现的方法很少(大多数情况下是一个方法)时,闭包可以提供另一种更优雅的解决方案。 但是,当属性和方法的数量变大时,最好实现一个类。 这是一个简单的示例,其中闭包可能比定义类和创建对象更可取。 但是,偏好是您的全部。 ```py def make_multiplier_of(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))) ``` **输出**: ```py 27 15 30 ``` [Python 装饰器](/python-programming/decorator)也广泛使用了闭包。 最后,最好指出可以发现外层函数中包含的值。 所有函数对象都具有`__closure__`属性,如果它是闭包函数,则该属性返回单元格对象的元组。 参考上面的示例,我们知道`times3`和`times5`是闭包函数。 ```py >>> make_multiplier_of.__closure__ >>> times3.__closure__ (<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,) ``` 单元格对象具有存储关闭值的属性`cell_contents`。 ```py >>> times3.__closure__[0].cell_contents 3 >>> times5.__closure__[0].cell_contents 5 ```