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()操作之后的。。。

提示到这大家猜也能猜到结果吧!!!!

更多相关文章

  1. 即使我返回2个变量,对象也不可迭代?
  2. 如何正确地获取在pysnmp中被捕获的变量的表行索引和命名值?
  3. python中查看变量内存地址的方法
  4. Shell脚本更改带变量的目录
  5. 在linux bash do循环中保持变量的值
  6. 堆栈/帧指针作为外部变量
  7. 《Linux命令行与shell脚本》笔记--第5章:使用Linux环境变量
  8. Ubuntu系统环境变量详解
  9. Debian下环境变量设置

随机推荐

  1. Android: Support Libraries for Android
  2. Android小米5安装包解析失败问题
  3. android studio 加载.proto不能生成xxxDr
  4. Android 使用Handler的PostDelayed方法实
  5. 安卓相关学习
  6. Android:简单的开场界面
  7. android布局控件的用法
  8. 解决:修改安卓system系统文件导致手机一直
  9. android属性动画爬坑之路
  10. Activity的android:launchMode