轻量级前端框架助力开发者提升项目效率与性能
967
2022-10-06
在Python中什么是闭包?能做什么?
1.什么是闭包
当我们在外部函数中定义了一个内部函数,并且内部函数能够读取到外部函数内的变量,这种函数我们就称为闭包。简单来说,闭包就是能够读取外部函数内的变量的函数。闭包的架子大概是这样:
def demo_outer(x): def demo_inner(y): print("x的值:{}, y的值:{}, x + y 的值:{}".format(x, y, x + y)) return demo_innerdo = demo_outer(12)do(34)
上面代码执行结果如下:
x的值:12, y的值:34, x + y 的值:46
上面的闭包代码,和我们之前学习的装饰器类似,我们在外部函数 demo_outer 下定义了一个内部函数 demo_inner ,并且外部函数的返回值就是内部函数,同时在内部函数中,我们引用到了外部函数的变量 x ,而闭包的作用就是可以将外层函数的变量保存在内存中而不被销毁。
2.闭包的实例
我们先准备一个函数add(),每次调用该函数都只能传一个数 num ,每次返回的结果都是基于上一次结果的值 sum 进行累加操作。例如,sum的默认值为0,如果我们依次调用 add(10)、add(20)、add(30) 后,期望得到的最终结果是 sum = 60。
对于该问题,因为需要在函数内部对函数外部的变量进行处理,我们可能会考虑使用 global 来处理。
sum = 0def get_add_sum(num): global sum sum += num return sumprint(get_add_sum(10)) # 输出:10print(get_add_sum(20)) # 输出:30print(get_add_sum(30)) # 输出:60print(sum) # 输出:60
对于上面的问题,除了使用全局变量外,我们还可以通过 闭包 来实现。
sum = 0def get_add_sum(sum): def add_num(num): nonlocal sum sum += num return sum return add_numadd = get_add_sum(sum)print(add(10)) # 输出:10print(add(20)) # 输出:30print(add(30)) # 输出:60print(sum) # 输出:0
在上面的闭包函数中,定义了外层函数和内层嵌套函数,执行过程中,调用外层函数 get_add_sum 返回的就是内层嵌套函数 add_num ,因为Python中函数也是对象,所以可以直接返回 add_num 。
我们再来看一个例子:
def outer(): res = [] for i in range(3): print("外部的i值:{}".format(i)) def inner(x): print("内部的i值:{}".format(i)) return i + x res.append(inner) return restemp = outer()res = [i(10) for i in temp]print(res)
上面代码的执行结果如下:
外部的i值:0外部的i值:1外部的i值:2内部的i值:2内部的i值:2内部的i值:2[12, 12, 12]
可以看到 res 的结果并不是 [10, 11, 12] ,因为 i 是外层函数的变量,并且其值是按 0,1,2 变化,因为该函数中无法保存外层函数的变量,故对于内部函数,其实际只能访问到最后外部变量的值 2 ,导致最终结果为:[12, 12, 12]。
在这里,我们可以使用闭包来保存函数的外部变量,修改代码如下:
def outer(i): print("外部的i值:{}".format(i)) def inner(x): print("内部的i值:{}".format(i)) return i + x return innerdef demo(): res = [] for i in range(3): res.append(outer(i)) return restemp = demo()res = [i(10) for i in temp]print(res)
上面代码的执行结果如下:
外部的i值:0外部的i值:1外部的i值:2内部的i值:0内部的i值:1内部的i值:2[10, 11, 12]
3.闭包和装饰器的区别
在Python中,闭包传递的参数是变量,装饰器传递的参数是函数对象,它们只是在传参内容上有不同。那么装饰器是不是属于闭包的一种呢,我们要怎么判断一个函数是否是闭包呢?
我们可以打印 闭包 和 装饰器 的属性 __closure__ ,如果一个函数是闭包,那么查看该属性将会返回一个cell对象组成的tuple对象。
'''学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def demo_outer(x): """ 闭包 """ def demo_inner(y): print("x的值:{}, y的值:{}, x + y 的值:{}".format(x, y, x + y)) return demo_innerdef demo_decorator(func): """ 装饰器 """ def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper@demo_decoratordef method(): passdo = demo_outer(5) # 闭包print("闭包的属性:{}".format(do.__closure__))dd = demo_decorator(method) # 装饰器print("装饰器的属性:{}".format(dd.__closure__))
执行结果如下:
闭包的属性:(
所以结合上面的结果,我们也可以这样理解:装饰器本质上就是一个闭包函数,它只是一个传递函数对象的闭包函数。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~