1、什么事闭包?
闭包的定义有很多种,下面是python官网给出的定义:
闭包是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
上述定义听起来似乎有点绕,直白点的定义如下:
闭包就是一个特殊的内部函数,具体特殊在哪里呢?就是该内部函数引用了外部作用域的一些变量(注意,外部作用于变量不包含全局变量),那么内部函数就被认为是闭包(closure)
2、闭包的本质
简单说,闭包的本质就是根据不同的配置信息得到不同的结果
3、闭包的例子
我们知道,人分为成年人跟未成年人,加入给定一个人的年龄,根据是否是未成年人打印出不同的信息,可以用如下实现,当然,这个需求可以直接根据用if判断分支处理,此处只是简单阐述闭包的用法
def outer(age): a = {} def get_info(name=None, work=None, age=age): if age < 18: a['name'] = name a['age'] = age else: a['name'] = name a['age'] = age a['work'] = work return a return get_info if __name__ == "__main__": p1 = outer(15) p2 = outer(20) print p1('zhangsan', None) print p2('lisi', 'pythoner')
先看下运行结果
我们来结合这段简单的代码分析下闭包
外部函数:outer()
内部函数:get_info()
外部作用域有个age
内部函数引用了外部作用域的age变量
分析到这就该确定get_info()是一个闭包了,因为闭包的定义只需满足两条:1、内部函数 2、引用了外部作用域的一个变量
结合官网给出的定义(函数和与其相关的引用环境而组合成的实体)来分析,函数就是get_info() 引用环境就是age
4、自由变量
按照函数的生命周期分析,在执行完p1=outer(15)之后,返回了一个函数对象赋值给p1,正常情况下局部变量age应该销毁了,但是为什么再执行p1()的时候还能访问到age呢?
这涉及到一个特殊的定义:自由变量, 自由变量的定义很简单,闭包所引用的外部作用域变量称为自由变量。
当一个变量变成自由变量之后,其作用域会发生相应的改变,本文不做具体的阐述,只需知道自由变量随闭包存活就可以了。
5、闭包操作自由变量所需要的注意事项
在上述例子中,闭包对自由变量做了更新操作,大家可能会觉得自由变量在闭包内随意操作,其实不然,有以下规则:
如果自由变量是可变对象(list,map...这里没有列出tuple是因为tuple是不可改变对象),那么闭包可以更新自由变量
如果自由变量是不可变对象(数值,字符窜,tuple...),那么闭包不可以更新自由变量,看下面两个例子
(1)自由变量为不可变对象
def foo(): a = 10 def bar(): a = a + 10 return a return bar if __name__ == "__main__": b = foo() print b()
如果运行这段代码,会得到以下结果
(2)自由变量为可变对象
def foo(): a = [] def bar(): a.append(100) return a return bar if __name__ == "__main__": b = foo() print b()
运行这段代码会输出:[100]
6、猜想
将上述程序稍作修改,请猜测运行结果
def foo(): a = [] def bar(): a.append(100) return a return bar if __name__ == "__main__": b = foo() c = foo() print b() print b() print c()
如果你能知道这段代码运行结果,恭喜你已经掌握闭包的含义了,如果不知道结果,请继续返回文章前面阅读
*提示:1、b = foo()跟c = foo()返回的是两个不同的对象,也就有两个自由变量,
2、自由变量的生命周期等同于闭包的生命周期,也就是说在第二次执行print b()的时候,自由变量是被第一次执行print b()操作之后的。。。
提示到这大家猜也能猜到结果吧!!!!