2013-11-12 11:00
闭包这个概念在 JavaScript 中讨论和使用得比较多,不过在 Python 中却不是那么显而易见,之所以说“不是那么”,是因为即使用到了,也没用注意到而已,比如定义一个 Decorator 时,就已经用到闭包了。网上对闭包的各种解释,感觉非常晦涩,在这里谈谈我的浅显认识:要形成闭包,首先得有一个嵌套的函数,即函数中定义了另一个函数,闭包则是一个集合,它包括了外部函数的局部变量,这些局部变量在外部函数返回后也继续存在,并能被内部函数引用。
举个例子
generate_power_func,它返回另一个函数,现在闭包形成的条件已经达到。
123456 |
|
nth_power,它能引用到外部函数的局部变量 n,而且即使 generate_power_func已经返回。把这种现象就称为闭包。具体使用一下。
12345 |
|
generate_power_func(4) 执行后, 创建和返回了 nth_power 这个函数对象,内存地址是 0x2C090C8,并且发现 raised_to_4 和它的内存地址相同,即 raised_to_4 只是这个函数对象的一个引用。先在全局命名空间中删除 generate_power_func,再试试会出现什么结果。
123 |
|
nth_power 是怎么知道 n 的值是 4,而且现在 generate_power_func甚至都不在这个命名空间了。对,这就是闭包的作用,外部函数的局部变量可以被内部函数引用,即使外部函数已经返回了。
closure_ 属性和 cell 对象
__closure__ 属性。__closure__
123456 |
|
raised_to_4 的 __closure__ 属性中有外部函数变量 n 的引用,通过内存地址可以发现,引用的都是同一个 n。如果没用形成闭包,则 __closure__ 属性为 None。对于 Python 具体是如何实现闭包的,可以查看 Python闭包详解,它通过分析 Python 字节码来讲述闭包的实现。
最后总结
闭包特性有着非常多的作用,不过都是需要时才会不经意的用上,不要像使用设计模式一样去硬套这些法则。这篇文章按照自己的理解翻译至 Python Closures Explained,可能和原文有些不同之处,如有疑惑,请查看原文。附上一些参考资料。
- 闭包的概念、形式与应用: 可以从其中了解闭包的应用
- Python闭包详解:从字节码出发了解 Python 闭包的实现机制
- 理解Javascript的闭包: 从 Javascript 的闭包中了解一些闭包特性,可以和 Python 作下对比