闭包
在 Python 中,函数也是一个对象。因此,我们在定义函数时,可以再嵌套定义一个函数,并将该嵌套函数返回,比如:
from math import pow def make_pow(n): def inner_func(x): # 嵌套定义了 inner_func return pow(x, n) # 注意这里引用了外部函数的 n return inner_func # 返回 inner_func
上面的代码中,函数 make_pow 里面又定义了一个内部函数 inner_func ,然后将该函数返回。因此,我们可以使用 make_pow 来生成另一个函数:
>> > pow2 = make_pow(2) # pow2 是一个函数,参数 2 是一个自由变量 >> > pow2 <function inner_func at 0x10271faa0 > >> > pow2(6) 36.0
我们还注意到,内部函数 inner_func 引用了外部函数 make_pow 的自由变量 n ,这也就意味着,当函数 make_pow 的生命周期结束之后, n 这个变量依然会保存在 inner_func 中,它被 inner_func 所引用。
>> > del make_pow # 删除 make_pow >> > pow3 = make_pow(3) Traceback(most recent call last): File "<stdin>", line 1, in < module > NameError: name 'make_pow' is not defined >> > pow2(9) # pow2 仍可正常调用,自由变量 2 仍保存在 pow2 中 81.0
---|---
像上面这种情况,一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数称为闭包( Closure )。
在上面的例子中, inner_func 就是一个闭包,它引用了自由变量 n 。
闭包的作用
闭包的最大特点就是引用了自由变量,即使生成闭包的环境已经释放,闭包仍然存在;
闭包在运行时可以有多个实例,即使传入的参数相同,比如:
>> > pow_a = make_pow(2) >> > pow_b = make_pow(2) >> > pow_a == pow_b False
利用闭包,我们还可以模拟类的实例。
这里构造一个类,用于求一个点到另一个点的距离:
from math import sqrt class Point(object): def __init__(self, x, y): self.x, self.y = x, y def get_distance(self, u, v): distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2) return distance >> > pt = Point(7, 2) # 创建一个点 >> > pt.get_distance(10, 6) # 求到另一个点的距离 5.0
用闭包来实现:
def point(x, y): def get_distance(u, v): return sqrt((x - u) ** 2 + (y - v) ** 2) return get_distance >> > pt = point(7, 2) >> > pt(10, 6) 5.0
可以看到,结果是一样的,但使用闭包实现比使用类更加简洁。
常见误区
闭包的概念很简单,但实现起来却容易出现一些误区,比如下面的例子:
def count(): funcs = [] for i in [1, 2, 3]: def f(): return i funcs.append(f) return funcs
在该例子中,我们在每次 for 循环中创建了一个函数,并将它存到 funcs 中。现在,调用上面的函数,你可能认为返回结果是 1, 2, 3,事实上却不是:
>> > f1, f2, f3 = count() >> > f1() 3 >> > f2() 3 >> > f3() 3
为什么呢?原因在于上面的函数 f 引用了变量 i ,但函数 f 并非立刻执行,当 for 循环结束时,此时变量 i 的值是3, funcs 里面的函数引用的变量都是 3,最终结果也就全为 3。
因此,我们应尽量避免在闭包中引用循环变量,或者后续会发生变化的变量。
那上面这种情况应该怎么解决呢?我们可以再创建一个函数,并将循环变量的值传给该函数,如下:
def count(): funcs = [] for i in [1, 2, 3]: def g(param): f = lambda: param # 这里创建了一个匿名函数 return f funcs.append(g(i)) # 将循环变量的值传给 g return funcs >> > f1, f2, f3 = count() >> > f1() 1 >> > f2() 2 >> > f3() 3
小结
闭包是携带自由变量的函数,即使创建闭包的外部函数的生命周期结束了,闭包所引用的自由变量仍会存在。
闭包在运行可以有多个实例。
尽量不要在闭包中引用循环变量,或者后续会发生变化的变量。
以上就是Python进阶:携带状态的闭包的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Python适合数据科学、Web开发和自动化任务,而C 适用于系统编程、游戏开发和嵌入式系统。 Python以简洁和强大的生态系统着称,C 则以高性能和底层控制能力闻名。

2小时内可以学会Python的基本编程概念和技能。1.学习变量和数据类型,2.掌握控制流(条件语句和循环),3.理解函数的定义和使用,4.通过简单示例和代码片段快速上手Python编程。

Python在web开发、数据科学、机器学习、自动化和脚本编写等领域有广泛应用。1)在web开发中,Django和Flask框架简化了开发过程。2)数据科学和机器学习领域,NumPy、Pandas、Scikit-learn和TensorFlow库提供了强大支持。3)自动化和脚本编写方面,Python适用于自动化测试和系统管理等任务。

两小时内可以学到Python的基础知识。1.学习变量和数据类型,2.掌握控制结构如if语句和循环,3.了解函数的定义和使用。这些将帮助你开始编写简单的Python程序。

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

Python3.6环境下加载Pickle文件报错:ModuleNotFoundError:Nomodulenamed...

如何解决jieba分词在景区评论分析中的问题?当我们在进行景区评论分析时,往往会使用jieba分词工具来处理文�...


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

Atom编辑器mac版下载
最流行的的开源编辑器

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器