python 函数进阶之闭包函数

 更新时间:2022年04月18日 15:58:16   作者:小可爱呦  
这篇文章主要介绍了python 函数进阶之闭包函数,内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程叫做闭包,里面的内函数是闭包函数,下文相关介绍需要的小伙伴可以参考一下

闭包函数

什么是闭包函数

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

# 外函数 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 闭包函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Pytorch to(device)用法

    Pytorch to(device)用法

    今天小编就为大家分享一篇Pytorch to(device)用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • 基于Python List的赋值方法

    基于Python List的赋值方法

    今天小编就为大家分享一篇基于Python List的赋值方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • Python中如何快速解析JSON对象数组

    Python中如何快速解析JSON对象数组

    由于浏览器可以迅速地解析JSON对象,它们有助于在客户端和服务器之间传输数据,本文将描述如何使用Python的JSON模块来传输和接收JSON数据
    2023-09-09
  • Python运算符重载的简单实例代码

    Python运算符重载的简单实例代码

    什么是运算符重载,就是让自定义的类生成的对象(实例)能够使用运算符进行操作,这篇文章主要给大家介绍了关于Python运算符重载的相关资料,需要的朋友可以参考下
    2022-01-01
  • tensorflow2.0与tensorflow1.0的性能区别介绍

    tensorflow2.0与tensorflow1.0的性能区别介绍

    今天小编就为大家分享一篇tensorflow2.0与tensorflow1.0的性能区别介绍,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • 解决keras使用cov1D函数的输入问题

    解决keras使用cov1D函数的输入问题

    这篇文章主要介绍了解决keras使用cov1D函数的输入问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • Django框架视图介绍与使用详解

    Django框架视图介绍与使用详解

    这篇文章主要介绍了Django框架视图介绍与使用,结合实例形式分析了Django框架视图的功能、配置、使用方法及相关操作注意事项,需要的朋友可以参考下
    2019-07-07
  • python matplotlib绘图详解大全(非常详细!)

    python matplotlib绘图详解大全(非常详细!)

    这篇文章主要给大家介绍了关于python matplotlib绘图详解的相关资料,matplotlib是python中用于绘制各种图像的模块,功能十分强大,通常与pandas模块搭配使用,可以生成各种样视的图片,用于数据的分析和展示,需要的朋友可以参考下
    2023-09-09
  • Python中字典的基本知识初步介绍

    Python中字典的基本知识初步介绍

    这篇文章主要介绍了Python中字典的基本知识初步介绍,是Python入门中的基础知识,需要的朋友可以参考下
    2015-05-05
  • Python必须了解的35个关键词

    Python必须了解的35个关键词

    这篇文章主要介绍了Python必须了解的35个关键词,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07

最新评论