python 闭包函数详细介绍


Posted in Python onApril 19, 2022

闭包函数

什么是闭包函数

如果内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程叫做闭包,里面的内函数是闭包函数。

# 外函数 outer
def outer():
# 外函数变量 num
var = '外函数局部变量'

# 内函数 inner
def inner():
# 内函数使用了外函数的变量 num
print('内函数使用了:' + var)

# 外函数将使用了外函数的局部变量的内函数返回
return inner

# 返回出的结果就是内函数 inner,现在inner就是一个闭包函数
func = outer()

# 执行返回出的 inner 函数
func() # 内函数使用了:外函数局部变量

下面是一个复杂的版本。
inner函数返回了函数x 和 y,x 和 y是外函数的内函数,虽然覆盖了原有的外函数的局部变量,但是这两个函数本质上还是外函数的布局变量,所以外函数返回了inner,inner就是一个闭包函数。
inner返回了外函数的x和y函数,x和y函数都是用了外函数的内函数num3,外函数返回inner,inner返回了x和y,所以变相的就是外函数返回了x和y,所以x和y也是闭包函数。

# 外函数
def outer():
# 外函数的局部变量
x = 1
y = 2
num3 = 3

# 内函数 x 重名变量 x
def x():
# 调用修改了 变量 num3
nonlocal num3
num3 *= 10
print(num3)

# 内函数 y 重名变量y
def y():
# 调用修改了 变量num3
nonlocal num3
num3 += 10
print(num3)

# 内函数inner
def inner():
# 返回了同级内函数 x y
return x, y

# 外函数最终返回了 inner函数
return inner

判断是否是闭包函数

方法

作用

\__closure__

获取闭包函数使用的局部变量

cell_contents

获取单元格对象当中的闭包函数

\__closure__

可以使用这个方法判断一个函数是否是一个闭包函数,因为闭包函数必须要使用外函数的局部变量,如果返回None就说明这个函数不是闭包函数,如果返回的是一个元组,说明这是一个闭包函数,元组中有cell单元格对象,一个单元格对象表示这个闭包函数使用了几个外函数的局部变量。
拿上述版本测试。

# 外函数
def outer():
# 外函数的局部变量
x = 1
y = 2
num3 = 3

# 内函数 x 重名变量 x
def x():
# 调用修改了 变量 num3
nonlocal num3
num3 *= 10
print(num3)

# 内函数 y 重名变量y
def y():
# 调用修改了 变量num3
nonlocal num3
num3 += 10
print(num3)

# 内函数inner
def inner():
# 返回了同级内函数 x y
return x, y

# 外函数最终返回了 inner函数
return inner


# 执行outer返回的结果是inner
func = outer() # func == inner

# 执行func返回的是 x y 函数
a, b = func()

# 使用__closure__测试这个几个函数是否是闭包函数
print(outer.__closure__)
print(func.__closure__)
print(a.__closure__)
print(b.__closure__)

'''
结果:除了外函数outer之外都返回了cell对象,说明inner x y 都是闭包函数
None
(<cell at 0x0000022F246AECA8: function object at 0x0000022F2466C400>, <cell at 0x0000022F247F3558: function object at 0x0000022F24850730>)
(<cell at 0x0000022F245D8708: int object at 0x00000000542280B0>,)
(<cell at 0x0000022F245D8708: int object at 0x00000000542280B0>,)
'''

cell_contents

虽然用​​__closure__​​获取到了闭包函数使用的元素,但是是以cell单元格对象的形式展示的,我们并不能看出这个使用的 元素到底是什么东西,可以使用​​cell_contents​​查看。

# 外函数
def outer():
# 外函数的局部变量
x = 1
y = 2
num3 = 3

# 内函数 x 重名变量 x
def x():
# 调用修改了 变量 num3
nonlocal num3
num3 *= 10
print(num3)

# 内函数 y 重名变量y
def y():
# 调用修改了 变量num3
nonlocal num3
num3 += 10
print(num3)

# 内函数inner
def inner():
# 返回了同级内函数 x y
return x, y

# 外函数最终返回了 inner函数
return inner


# 执行outer返回的结果是inner
func = outer() # func == inner


# 使用__closure__返回了闭包函数使用的局部变量
tup = func.__closure__

# 使用 cell_contents 查看这些局部变量都是些什么
res = tup[0].cell_contents
print(res)
res = tup[1].cell_contents
print(res)

'''
结果:可以看到inner 使用的局部变量使用外函数的内函数 x 和 y
None
<function outer.<locals>.x at 0x0000018D5A66C400>
<function outer.<locals>.y at 0x0000018D5A850730>
'''

闭包函数的特点

让我们回忆一下,函数中创建的变量是一个什么变量?是一个局部变量。
局部变量的生命周期是多久?是等局部作用结束之后就会被释放掉。

如果内函数使用了外函数的局部变量,那么这个变量就与闭包函数发生了绑定关系,就延长该变量的生命周期。实际上就是内存给它存储了这个值,暂时不释放。

下面的例子中,我们调用了函数outer并赋予了参数val的值为10,但是outer执行完之后,outer的val并没有被释放,而是被闭包函数inner延长了生命周期,所以val可以一直在inner中按照调用outer函数的时候赋予的值10进行运算。
因为内函数inner使用了外函数outer的变量val,且outer返回了inner,所以inner是一个闭包函数。因为inner是一个闭包函数,当它调用outer的变量val时就会延长val的生命周期,val就不会随着outer的调用结束而被释放
而是存储在了内存当中,当inner再次使用val时,val就会将值赋予inner。

def outer(val):
def inner(num):
return val + num

return inner

func = outer(10)
res = func(10)
print(res) # 20
res = func(20)
print(res) # 30

闭包函数的意义

闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装包保护的作用,使外部无法访问。
我们做一个模拟鼠标点击的事件,可以看得出闭包函数封装保护数据的作用。
现在只是一个普通的函数,它无法对我们使用的变量的数据进行保护,在全局中这个数据可以被随意的修改。

# 不使用闭包,当函数中调用全局变量时,外部也可以控制变量

# 全局变量
num = 0

# 点击事件
def click_num():
# 每执行一次数值 +1
global num
num += 1
print(num)

# 执行点击事件
click_num() # 1
click_num() # 2
click_num() # 3

# 在全局重新定义了num的值,num的值就被彻底的改变了,但是我们的程序的数据本不该如此。
num = 1231231

click_num() # 1231232
click_num() # 1231233
click_num() # 1231234

现在使用闭包函数对数据进行封装保护,就不能在全局中随意的修改我们使用的数据。

# 我们将需要使用的数据放在外函数中,点击事件作为内函数也放在外函数中,然后作为闭包返回。
def clickNum():
# 需要使用的数据
num = 0

# 内函数(真正执行点击事件的函数)
def inner():
# 执行点击事件
nonlocal num
num += 1
print(num)

# 作为闭包返回
return inner

# 返回闭包
click_num = clickNum() # # click_num == inner

# 执行点击事件
click_num() # 1
click_num() # 2
click_num() # 3

# 全局中修改 num 的值
num = 123412341234

# 闭包函数对数据的封装保护起到了作用
click_num() # 4
click_num() # 5
click_num() # 6

到此这篇关于python 函数进阶之闭包函数的文章就介绍到这了!

Python 相关文章推荐
Python实现登录人人网并抓取新鲜事的方法
May 11 Python
python获取一组汉字拼音首字母的方法
Jul 01 Python
Python使用functools模块中的partial函数生成偏函数
Jul 02 Python
python批量赋值操作实例
Oct 22 Python
python实现浪漫的烟花秀
Jan 30 Python
Python学习笔记基本数据结构之序列类型list tuple range用法分析
Jun 08 Python
python3+PyQt5 数据库编程--增删改实例
Jun 17 Python
django最快程序开发流程详解
Jul 19 Python
Tensorflow之梯度裁剪的实现示例
Mar 08 Python
Python使用pycharm导入pymysql教程
Sep 16 Python
Python基于callable函数检测对象是否可被调用
Oct 16 Python
python+excel接口自动化获取token并作为请求参数进行传参操作
Nov 10 Python
Python  lambda匿名函数和三元运算符
Apr 19 #Python
Python使用mitmproxy工具监控手机 下载手机小视频
使用Python通过企业微信应用给企业成员发消息
Python用any()函数检查字符串中的字母以及如何使用all()函数
Apr 14 #Python
python在package下继续嵌套一个package
Apr 14 #Python
Github 使用python对copilot做些简单使用测试
使用Python拟合函数曲线
Apr 14 #Python
You might like
PHP 替换模板变量实现步骤
2009/08/24 PHP
PHP实现事件机制实例分析
2015/06/26 PHP
yii分页组件用法实例分析
2015/12/28 PHP
Thinkphp 中 distinct 的用法解析
2016/12/14 PHP
Yii2框架中使用PHPExcel导出Excel文件的示例
2017/08/09 PHP
JS继承 笔记
2011/07/13 Javascript
使用jQuery.fn自定义jQuery翻页插件
2013/01/20 Javascript
二叉树先序遍历的非递归算法具体实现
2014/01/09 Javascript
JavaScript在IE和FF下的兼容性问题
2014/05/19 Javascript
JavaScript 事件绑定及深入
2015/04/13 Javascript
用js动态添加html元素,以及属性的简单实例
2016/07/19 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
详细谈谈AngularJS的子级作用域问题
2016/09/05 Javascript
VueJS全面解析
2016/11/10 Javascript
Angularjs的键盘事件的绑定
2017/07/27 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
Vue 实例事件简单示例
2019/09/19 Javascript
微信小程序实现抖音播放效果的实例代码
2020/04/11 Javascript
python抓取网页中链接的静态图片
2018/01/29 Python
python中利用h5py模块读取h5文件中的主键方法
2018/06/05 Python
将Python字符串生成PDF的实例代码详解
2019/05/17 Python
基于Python的Post请求数据爬取的方法详解
2019/06/14 Python
django最快程序开发流程详解
2019/07/19 Python
python tkinter实现屏保程序
2019/07/30 Python
python 数据提取及拆分的实现代码
2019/08/26 Python
tensorflow 分类损失函数使用小记
2020/02/18 Python
python实现门限回归方式
2020/02/29 Python
Python控制台实现交互式环境执行
2020/06/09 Python
基于Python 的语音重采样函数解析
2020/07/06 Python
中国制造网:Made-in-China.com
2019/10/25 全球购物
德国消费电子产品购物网站:Guter Kauf
2020/09/15 全球购物
事业单位鉴定材料
2014/05/25 职场文书
关于旅游的活动方案
2014/08/15 职场文书
乡镇机关党员民主评议表自我评价
2014/09/21 职场文书
社区三八妇女节活动总结
2015/02/06 职场文书
z-index不起作用
2021/03/31 HTML / CSS