闭包的概念
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
—— 维基百科)
用比较容易懂的人话说,就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。看例子。
In [15]: def func(name):
...: def inner_func(age):
...: print('name',name,'age',age)
...: return inner_func
...:
In [17]: bb = func('Tom')
In [18]: bb
Out[18]: <function __main__.func.<locals>.inner_func>
In [19]: type(bb)
Out[19]: function
In [20]: bb(18)
name Tom age 18
这里面调用func
的时候就产生了一个闭包——inner_func
,并且该闭包持有自由变量——name
,因此这也意味着,当函数func
的生命周期结束之后,name
这个变量依然存在,因为它被闭包引用了,所以不会被回收。
另外再说一点,闭包并不是Python
中特有的概念,所有把函数做为一等公民的语言均有闭包的概念。
闭包的作用
闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数(也即闭包),此时即便生成闭包的环境(父函数)已经释放,闭包仍然存在,这个过程很像类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活,现举一例:假设我们仅仅想打印出各类动物的叫声,分别以类和闭包来实现:
类:
In [23]: class Animal():
...: def __init__(self,animal):
...: self.animal = animal
...: def sound(self,voice):
...: print(self.animal,':',voice,'...')
...:
In [24]: dog = Animal('dog')
In [25]: dog.sound('wang~wang~')
dog : wang~wang~ ...
In [26]: dog.sound('wo~wo~')
dog : wo~wo~ ...
闭包:
In [28]: def voice(animal):
...: def sound(voc):
...: print(animal,':',voc,'...')
...: return sound
...:
In [29]: dog = voice('dog')
In [30]: dog('wangwangwang~')
dog : wangwangwang~ ...
In [31]: type(dog)
Out[31]: function
In [32]: dog
Out[32]: <function __main__.voice.<locals>.sound>
可以看到输出结果是完全一样的,但显然类的实现相对繁琐,且这里只是想输出一下动物的叫声,定义一个Animal 类
未免小题大做,而且 voice 函数
在执行完毕后,其作用域就已经释放,但Animal 类
及其实例 dog
的相应属性却一直贮存在内存中:
In [33]: id(Animal.sound)
Out[33]: 2044388328584
而这种占用对于实现该功能后,则是没有必要的。
除此之外,闭包还有很多其他功能,比如用于封装等,另外,闭包有效的减少了函数参数的数目,这对并行计算非常有价值,比如可以让每台电脑负责一个函数,然后串起来,实现流水化的作业等。