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. 闭包之间内存隔离。
相关推荐
IT_陈寒16 分钟前
Python开发者必看:这5个鲜为人知的Pandas技巧让你的数据处理效率提升50%
前端·人工智能·后端
豆苗学前端24 分钟前
写给女朋友的第一封信,测试方法概论
前端·后端·设计模式
武子康1 小时前
大数据-140 ClickHouse CollapsingMergeTree详解 外部数据源最小闭环HDFS/MySQL/Kafka
大数据·后端·nosql
m0_736927041 小时前
使用 Python 将 PowerPoint 转换为 Word 文档
java·开发语言·后端·职场和发展·c#
杜子不疼.1 小时前
【Rust】路由匹配与参数提取:从 match 语句到 axum 的类型魔法
开发语言·后端·rust
qq_12498707531 小时前
基于Flask的穷游网酒店数据分析系统(源码+论文+部署+安装)
后端·python·flask·毕业设计
稚辉君.MCA_P8_Java1 小时前
Java 基本数据类型 - 四类八种
java·linux·后端·mysql·架构
爱吃烤鸡翅的酸菜鱼2 小时前
如何掌握【Java】 IO/NIO设计模式?工厂/适配器/装饰器/观察者模式全解析
java·开发语言·后端·设计模式·nio
golang学习记2 小时前
替代Postman,Github 38k star,这款API工具彻底火了!
后端
狂奔小菜鸡2 小时前
Day7 | Java的流程控制详解
java·后端·编程语言