Python中的闭包

英文称之为Closure,中文译为闭包,闭包的概念也并不是Python独有的,Javascript等高级语言中也存在闭包的概念。那什么是闭包?有一个经典的公式可以回答这个问题:

复制代码
闭包 = 内部函数 + 引用环境

这个公式非常清楚地说明,闭包本质上是具备"封闭"上下文环境的函数。所谓"封闭",是说该函数的上下文环境不会随着函数调用结束而销毁,实际上会持久驻留内存。众所周知,函数通常定义在全局上下文,而闭包函数定义在函数内部,全局上下文也是持久驻留的,把函数定义在全局上下文中也可以有相同效果,那闭包有什么不一样的地方?答案是可以避免全局变量的污染。

接下来,我们从简单闭包开始,逐步探讨下闭包的使用。

1、简单闭包

首先最简单的闭包是外部函数只传递一个函数引用和内部函数不带参数的闭包。我们在Pycharm中演示下简单闭包:

在上图的代码中,有以下几个关键点:

  1. 定义一个outer_func,outer_func的参数为一个函数引用func;
  2. 在outer_func中定义inner_func,并返回inner_func的引用;
  3. inner_func调用outer_func中传递的func引用的函数;
  4. 全局定义一个没有参数的print_info函数;
  5. 通过outer_func(print_info)得到f,此时的f指向outer_func中的inner_func已用
  6. 调用函数f

运行结果为:

通过简单闭包的演示可以看出,闭包中的引用环境主要是外部函数的变量,包括外部函数参数和外部函数中定义的变量,这个闭包在整个运行环境中,外部函数的参数和变量是一直被"锁"在内存中的,这也是调用f时还能访问func的原因。

当然,实际应用中func不可能没有参数,接下来让我们分析下带参数的闭包。

2、带参闭包

所谓带参闭包,是指闭包函数可以带参数,也就是上节中的inner_func可以带参数。我们在Pycharm演示下:

运行结果:

通过增加info,可以让闭包传递参数,稍有经验的开发者一眼就能看出这种带不可变参数的闭包不够通用,因为不可能参数增加一个就再定义一个闭包。在Python中,一旦涉及可变参数,需要使用args和**kwargs,好了,我们用args和**kwargs改造下上面的闭包:

运行结果:

3、闭包隔离

前面两节中,我们定义完闭包后,在使用过程中只创建了一个闭包函数,现在我们在Pycharm中做如下实验:

运行结果:

要提一下的是,在outer_func中定义了count,如果在inner_func只是读取count的话直接使用count即可,如果在inner_func中要写count,则需要在inner_func中声明nonlocal,与普通函数中修改全局变量时使用global类似,只不过nonlocal修饰的变量是外部函数中的变量。在本实验中,使用outer_func(print_info)定义两个"相同"的闭包f1和f2,f1调用3次,f2调用1次,从运行结果来看f1中的count虽然增加了,但是并不影响f2中的count,这说明了闭包一个很重要的特点:内存隔离。也就是说两个闭包函数的引用环境是独立的,彼此不影响,就像类的实例对象一样。

4、结尾

经过前面三节的分析之后,我们再回顾下闭包概念的经典公式:

复制代码
闭包 = 内部函数 + 引用环境

可以简单总结下:

  1. 闭包是定义在一个函数内部的函数;
  2. 外部函数传递一个函数引用给内部函数,并返回内部函数引用;
  3. 内部函数可以访问外部函数的变量,并调用外部函数传递的函数引用;
  4. 闭包之间内存隔离。
相关推荐
youliroam1 小时前
ESP32-S3+OV2640简单推流到GO服务
开发语言·后端·golang·esp32·ov2640
码luffyliu2 小时前
从 2 小时价格轮询任务通知丢失,拆解 Go Context 生命周期管控核心
后端·golang·go
a努力。2 小时前
宇树Java面试被问:方法区、元空间的区别和演进
java·后端·面试·宇树科技
码事漫谈2 小时前
二叉树中序遍历:递归与非递归实现详解
后端
码事漫谈2 小时前
跨越进程的对话之从管道到gRPC的通信技术演进
后端
无限大63 小时前
为什么"数据压缩"能减小文件大小?——从冗余数据到高效编码
后端
用户729429432233 小时前
kubernetes/k8s全栈技术讲解+企业级实战项目课程
后端
用户729429432233 小时前
基于Dubbo的分布式系统架构+事务解决方案
后端
程序员鱼皮3 小时前
什么是 RESTful API?凭什么能流行 20 多年?
前端·后端·程序员
+VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue健身房管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计