[关闭]
@songying 2018-07-24T10:46:35.000000Z 字数 1462 阅读 1132

python 闭包

python高级特性


只有涉及嵌套函数时才有闭包问题。

什么是闭包?

  1. objectname.__code__.co_freevars # 返回该对象中的自由变量名

闭包是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定。
注意,只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量。

闭包的三个条件

  • 必须包含一个嵌套函数
  • 嵌套函数必须引用封闭函数中定义的值(自由变量)
  • 封闭函数必须返回嵌套函数

为什么要使用闭包

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。

一般来说, 当对象中只有一个方法时,这时使用闭包是更好的选择,这比用类来实现更优雅。

__closure__属性

所有函数都有一个 __closure__属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell 对象 组成的元组对象。cell 对象的cell_contents 属性就是闭包中的自由变量。

  1. >>> adder.__closure__
  2. >>> adder5.__closure__
  3. (<cell at 0x103075910: int object at 0x7fd251604518>,)
  4. >>> adder5.__closure__[0].cell_contents
  5. 5

这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell_contents中了。

不可变对象与闭包

  1. def make_averager():
  2. count = 0
  3. total = 0
  4. def averager(new_value):
  5. count += 1
  6. total += new_value
  7. return total / count
  8. return averager
  9. >>> avg = make_averager()
  10. >>> avg(10)
  11. Traceback (most recent call last):
  12. ...
  13. UnboundLocalError: local variable 'count' referenced before assignment
  14. >>>

因此,针对第二种情况, python引入nonlocal声明,它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。如果为 nonlocal 声明的变量赋予新值,闭包中保存的绑定会更新。

正确的方式如下:

  1. def make_averager():
  2. count = 0
  3. total = 0
  4. def averager(new_value):
  5. nonlocal count, total
  6. count += 1
  7. total += new_value
  8. return total / count
  9. return averager
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注