有这样一个函数:
def multipliers(): return [lambda x :i*x for i in range(4)] print([m(2) for m in multipliers()])
运行multipliers()函数后打印的结果让我很吃惊,第一感觉是打印【0,2,4,6】,但是实际运行结果【6,6,6,6】,后来发现是闭包函数的原因。
什么是闭包函数呢?
闭包函数满足的条件:
1.定义一个外部函数内嵌一个内部函数
2.内部函数要引用外部函数的变量
3.同时外部函数的返回值必须是内部函数
闭包函数例子:
def outfunc(x): def innerfunc(): print('平方运算后的结果是',x*x) return innerfunc res = outfunc(10) res()
打印结果:平方运算后的结果是 100
闭包函数的定义听起来跟装饰器差不多,但是也有差别,装饰器传递的参数是函数,闭包函数传递的参数是变量,除此之外闭包函数跟装饰器没有什么区别,也可以说装饰器是闭包函数的一种特殊形式。闭包的作用是把外部函数的变量保存在内存中不被销毁。我们发现上面的例子中还用到了lambda匿名函数,这里也对匿名函数做一下简单的介绍。
什么是匿名函数呢?
匿名函数在编程中也是经常用到的函数,匿名函数顾名思义就是没有名字的函数,当我们需要实现一个简单的功能并且用完就不再需要重复使用的时候,匿名函数就是最好的选择。使用lambda表达式定义一个匿名函数,其结构是这样的:result = lambda[arg1[,arg2,...,argn]]:expression
1.result:用于调用lambda表达式
2.arg1[,arg2,...,argn]:可选参数,用来指定要传递的参数列表,多个参数用逗号进行分隔
3.expression:必选参数,用于指定一个实现具体功能的表达式,如果有参数的情况下,这个表达式将会应用这些参数。
【注意:在使用lambda表达式的时候,参数可以有多个,但是表达式必须有且仅有一个,即只能返回一个值,并且不能出现其他的非表达式的语句】
使用匿名函数的一个小例子:
import math r = 10 result = lambda r:math.pi*r*r print('半径为{}的圆的面积是{}'.format(r,result(10)))
打印结果:半径为10的圆的面积是314.1592653589793
现在言归正传,开篇的函数为什么打印的结果是【6,6,6,6】呢?
我们知道一个函数运行结束过后,函数内部的所有东西都会被释放掉,包括局部局部变量,但是如果外部函数在结束的时候发现自己的局部变量被内部函数引用,就会把这个局部变量绑定给内部函数,然后再结束外部函数。
在此处闭包函数返回内部函数的引用,即lambda表达式定义的函数,外函数结束时会将内函数绑定的局部变量(即闭包变量)绑定给内函数。延迟绑定指的是只有在调用内函数的时候才会访问闭包变量指向的对象。当执行[m(2) for m in multipliers()]的时候,会运行multipliers函数,且multipliers函数中有个for循环,当我们在执行m(2)的时候,for 循环已经执行完成了,此时i的值已经是3了,这时候才开始把i的值与内部函数进行绑定,运行2*3=6,所以得到的结果是【6,6,6,6】