python 函数进阶之闭包函数

目录
  • 闭包函数
    • 什么是闭包函数
    • 判断是否是闭包函数
    • \__closure__
    • cell_contents
    • 闭包函数的特点
    • 闭包函数的意义

闭包函数

什么是闭包函数

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

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

(0)

相关推荐

  • 详解python函数的闭包问题(内部函数与外部函数详述)

    python函数的闭包问题(内嵌函数) >>> def func1(): ... print ('func1 running...') ... def func2(): ... print ('func2 running...') ... func2() ... >>> func1() func1 running... func2 running... 内部函数func2作用域都在外部函数func1作用域之内 如果试图在外部函数的外部调用内部函数将会报错 >>

  • Python 中的函数装饰器和闭包详解

    函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念. 装饰器的基本概念 装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数.装饰器可以修改这个函数再将其返回,也可以将其替换为另一个函数或者可调用对象. 例如:有个名为 decorate 的装饰器: @decorate def target(): print('running target()') 上述代码的写法和以下写法的效果是一样的: def target(): print('running targe

  • python中的闭包函数

    闭包函数初探 通常我们定义函数都是这样定义的 def foo(): pass 其实在函数式编程中,函数里面还可以嵌套函数,如下面这样 def foo(): print("hello world in foo") def bar(): print("hello world in bar") 此时我们调用foo函数,执行结果会是什么样子的呢?? hello world in foo 结果如上所示,只会执行foo函数的第一层函数,bar函数是不会被执行的.为什么呢 实际上

  • Python闭包函数定义与用法分析

    本文实例分析了Python闭包函数定义与用法.分享给大家供大家参考,具体如下: python的闭包 首先python闭包的作用,一个是自带作用域,另一个是延迟计算. 闭包是装饰器的基础. 闭包的基本形式: def 外部函数名(): 内部函数需要的变量 def 内部函数名() 引用外部的变量 return 内部函数 需要注意的是: 函数的作用域关系在函数定义阶段就已经固定,与调用位置无关. 无论函数在何处调用,都需要回到定义阶段去找对应的作用域关系. 例子: # -*- coding:utf-8

  • Python函数对象与闭包介绍

    目录 一 函数对象 1.1 函数可以被引用 1.2 函数可以作为容器类型的元素 1.3 函数可以作为参数传入另外一个函数 1.4 函数的返回值可以是一个函数 二 闭包函数 2.1 闭与包 2.2 闭包的用途 一 函数对象 函数对象指的是函数可以被当做’数据’来处理,具体可以分为四个方面的使用 1.1 函数可以被引用 >>> def add(x,y): ... return x+y ... >>> func=add >>> func(1,2) 3 1.2

  • python 函数进阶之闭包函数

    目录 闭包函数 什么是闭包函数 判断是否是闭包函数 \__closure__ cell_contents 闭包函数的特点 闭包函数的意义 闭包函数 什么是闭包函数 如果内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程叫做闭包,里面的内函数是闭包函数. # 外函数 outer def outer(): # 外函数变量 num var = '外函数局部变量' # 内函数 inner def inner(): # 内函数使用了外函数的变量 num print('内函数使用了:' + va

  • Python函数基础实例详解【函数嵌套,命名空间,函数对象,闭包函数等】

    本文实例讲述了Python函数基础用法.分享给大家供大家参考,具体如下: 一.什么是命名关键字参数? 格式: 在*后面参数都是命名关键字参数. 特点: 1.约束函数的调用者必须按照Kye=value的形式传值. 2.约束函数的调用者必须用我们指定的Key名. def auth(*args,name,pwd): print(name,pwd) auth(pwd='213',name='egon') def register(name,age): print(type(name),type(age)

  • Python基础globlal nonlocal和闭包函数装饰器语法糖

    目录 一.global与nonlocal 1.global 2.nonlocal 二.函数名的多种用法 三.闭包函数 1.什么是闭包函数 2.闭包函数需满足的条件 3.闭包函数的作用 4.闭包函数的实际应用 四.装饰器 1.装饰器推导流程 2.装饰器语法糖 3.装饰器模板 一.global与nonlocal 1.global 在py文件中,一般无法调用函数体内变量名,而global可使函数体代码内的变量名直接在函数体外部调用,条件是在需要调用的代码体中使用global 调用需要的变量名 未使用g

  • 一文了解JavaScript闭包函数

    目录 变量作用域 闭包的概念 闭包的用途 闭包的缺点 最后总结一下闭包的好处与坏处 总结 变量作用域 要理解JavaScript闭包,就要先理解JavaScript的变量作用域. 变量的作用域有两种:全局的和局部的(全局变量和局部变量) JavaScript中,在函数内部可以直接读取到全局变量. var n=10 function fn(){ alert(n) } fn() //10 而在函数外部无法读取到函数内部的变量. function fn(){ var n=10; } fn() aler

  • Python函数进阶之迭代器的原理与使用详解

    目录 什么是迭代器 概念 特征 惰性序列 检查可迭代对象 定义迭代器 使用iter函数 使用__iter__方法 判断迭代器 检查内置方法 使用collections模块 调用迭代器 使用next方法和函数 什么是迭代器 能被 next 指针调用,并不断返回下一个值的对象,叫做迭代器.表示为Iterator,迭代器是一个对象类型数据. 概念 迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,单纯的重复并不是迭代. 特征 迭代器并不依赖索引,而通过 next

  • Python函数进阶与文件操作详情

    目录 一.作业回顾 1.格式化输出与%百分号 2.字符串切片 3.字典的定义 二.引用变量与可变.非可变类型 1.引用变量 聊聊变量在内存底层的存储形式 如何验证Python中变量的引用关系 把一个变量赋予给另外一个变量的影响 2.Python中可变和非可变数据类型 问题1:在Python中一共有几种数据类型? 问题2:如何判断一个数据类型是可变类型还是非可变类型? 3.可变类型与非可变类型在函数中的应用 可变类型 不可变类型 三.函数递归(重点难点) 1.前言 2.递推算法 3.什么是递归算法

  • python进阶教程之函数对象(函数也是对象)

    秉承着一切皆对象的理念,我们再次回头来看函数(function).函数也是一个对象,具有属性(可以使用dir()查询).作为对象,它还可以赋值给其它对象名,或者作为参数传递. lambda函数 在展开之前,我们先提一下lambda函数.可以利用lambda函数的语法,定义函数.lambda例子如下: 复制代码 代码如下: func = lambda x,y: x + y print func(3,4) lambda生成一个函数对象.该函数参数为x,y,返回值为x+y.函数对象赋给func.fun

随机推荐