精彩的ython--闭包

来源:互联网 发布:matlab绘制数据分布图 编辑:程序博客网 时间:2024/05/17 08:07

早在6年前就开始用pyhton了,真心很喜欢它,虽然后来用的很少。只要你能想到的,用python都能很简单、迅速的实现!  这几天又用它写了个测试小程序,回想起曾经用过的python知识,有些都模糊了。 所以,从今天开始,尽可能的做些记录吧。但不会是按照学习pyhon的过程中的那种一步步由浅入深的,就是想到什么、遇到什么,就记录、复习下。

今天就从闭包开始。

首先, 这个文章的第一部分是闭包的代码实例,摘自:  http://www.cnblogs.com/vamei/archive/2012/12/15/2772451.html。


闭包

函数是一个对象,所以可以作为某个函数的返回结果

def line_conf():    def line(x):        return 2*x+1    return line       # return a function objectmy_line = line_conf()print(my_line(5))       

上面的代码可以成功运行。line_conf的返回结果被赋给line对象。上面的代码将打印11。

如果line()的定义中引用了外部的变量,会发生什么呢?

def line_conf():    b = 15    def line(x):        return 2*x+b    return line       # return a function objectb = 5my_line = line_conf()print(my_line(5))       

我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。

上面的代码将打印25,也就是说,line所参照的值是函数对象定义时值,而不是使用时的值。

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:

def line_conf():    b = 15    def line(x):        return 2*x+b    return line       # return a function objectb = 5my_line = line_conf()print(my_line.__closure__)print(my_line.__closure__[0].cell_contents)

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是整数15,也就是我们创建闭包时的环境变量b的取值。

其次, 引用另一个博文(http://developer.51cto.com/art/201006/208139.htm)的对闭包的定义来总结闭包:

闭包是由函数和与其相关的引用环境组合而成的实体。比如参考资源中就有这样的的定义:在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。

闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。

闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。

最后, 一点思考、隐申。 yield语句的背后。

       我的理解, yield背后也是引入了一个对象来保存yield所在函数的代码以及环境,这样每次调用后时都能记录下该次调用的环境变量值,在下次调用时再使用这些值。

       当然,这是我个人的一点猜测,能帮助我理解、掌握yield。真实的机制,有兴趣的朋友可以深入去探究。