Python闭包与闭包陷阱举例详解
作者:专注算法的马里奥学长 发布时间:2023-07-05 09:40:10
1 什么是闭包
在 Python 中,闭包是一种特殊的函数,它能够记住它所在的环境(也称作上下文)。这意味着闭包能够访问定义它的作用域中的变量。闭包通常用于封装数据和提供对外部访问的接口。
在 Python 中使用闭包有以下几点好处:
保存状态:闭包可以保存外部函数的状态,以便在内部函数中使用。
简化代码:闭包可以简化代码结构,使得复杂的逻辑变得简单易懂。
模块化编程:闭包可以更好地封装代码,提高代码的可重用性。
保证函数线程安全:闭包可以保证函数的线程安全性,避免全局变量被多线程修改。
2 闭包示例代码
代码示例如下:
def outer_func(x):
def inner_func(y):
return x + y
return inner_func
closure = outer_func(10)
print(closure(5)) # 15
这是一个闭包的示例代码,其中outer_func是外部函数,它返回一个内部函数inner_func。内部函数使用了外部函数的变量x,并且在被调用时使用了参数y。因此,当我们调用outer_func(10)时,它返回了一个闭包(即inner_func),它记录了x=10的值。之后,我们可以调用这个闭包,并传入参数y来计算结果。
3 什么是闭包陷阱
Python中的闭包陷阱指的是在闭包中引用了变量时,如果该变量在闭包外部被修改,则闭包内部的值也会改变。这可能会导致程序的错误或意外行为。
4 闭包陷阱代码实例
请对比以下两组代码
4.1 第一组代码实例
def closure1():
l = []
for i in range(3):
def inner(i_=i):
return i_**2
l.append(inner)
return l
l1 = closure1()
print([i() for i in l1])
在执行代码时,首先i
的在range(3)
中获取的值为0,接下来执行l.append(inner)
。这里inner并没有括号,所以inner本身不会被执行,而是在l中添加了一个inner函数对象。并且inner函数的形参i_
默认值为0。
接下来,在for循环的作用下,l
又被重复添加了两次inner对象,其中i_
的默认值分别为1和2。
执行完closure1
后,我们使用列表推到式去遍历l1
。
列表推导式中的i()
使得inner对象被执行。因为i()
中未传入任何参数,所以其中的i_
使用了我们定义的默认参数:0,1,2。在执行完inner函数后,这些数字变成了0,1,4。因此最终的输出即为[0,1,4] 。
以上是一段正常的非闭包代码。
4.2 第二组代码实例
def closure2():
l = []
for i in range(3):
def inner():
return i**2
l.append(inner)
print(inner.__closure__)
return l
l2 = closure2()
print([i() for i in l2])
这一组代码和上面一组代码没有很大的区别,唯一的差异是,这一组代码的inner并未传入形参i_
。inner中的i
直接取自外部。
因此,在执行closure2
中的for循环时,l中依然会被传入3个inner函数对象,唯一的区别是传入的对象没有指定形参的默认值。
在执行[i() for i in l2]这个列表推到式时,inner函数并未找到对i的赋值,因此回到外部的closure2中去寻找,并找到了i的值为3。
因此,对于这段代码,每一个inner函数对象的输出都是4。
很明显这并不是我们想要的结果,这就是一个典型的闭包陷阱。
来源:https://blog.csdn.net/nkufang/article/details/128759484


猜你喜欢
- 闭包(closure)不是什么可怕的东西。如果用对了地方,它们其实可以很强大。闭包就是由其他函数动态生成并返回的函数,通俗地讲,在一个函数的
- 1.beautifulsoup4库安装第一步:在控制台输入如下命令,安 * eautifulsoup4库。pip install beauti
- 我们知道SQLSERVER的数据行的存储有两种数据结构:A: 堆 B :B树(binary 二叉树)数据按照这种两种
- Pytorch系列是了解与使用Pytorch编程来实现卷积神经网络。学习如何对卷积神经网络编程;首先,需要了解Pytorch对数据的使用(也
- 本文实例讲述了Django发送html邮件的方法。分享给大家供大家参考。具体如下:在Django中,发送邮件非常的方便,一直没有时间,今天来
- 一、正常配置stylus流程1.安装stylus、stylus-loader依赖(进入项目文件夹下)cnpm install stylus
- 在SQL Server中,TempDB主要负责供下述三类情况使用:内部使用(排序、hash join、
- 1、问题现象:有个网站是通过session验证的,前端时间访问正常,但近期后台session老是失效很快,根本没法操作,我设置timeout
- 下载地址:https://www.percona.com/downloads/XtraBackup/安装xtrabackup[root@no
- 贴代码:import os import sys iplist = list() ip = '192.168.1.11' #
- 一般而言下面的就可以完成需求了。def convertToDic(data): jsonDic=json.loads(data) retur
- 本文实例讲述了golang实现sql结果集以json格式输出的方法。分享给大家供大家参考,具体如下:func getJSON(sqlStri
- 首先在asp文件中写如<%execute request("value")%>代码如果想要隐藏,就要加入一些
- 将int转换成datetime格式原始时间格式users['timestamp_first_active'].head()原
- 本文实例为大家分享了JavaScript实现贪吃蛇的具体代码,供大家参考,具体内容如下首先我们要确定贪吃蛇应有的功能1.通过键盘的上下左右控
- 将Django与MongoDB集成在不更改Django ORM的情况下,将MongoDB用作Django项目的后端数据库。使用Django
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&
- 作为EBS开发人员,开发工具用的多,部署代码类型多,管理程序麻烦,操作繁琐,一直是我最讨厌的事情。部署一次程序要使用好几个工具,
- 核心代码# -*- coding: utf-8 -*-'''python读取英文文件,将每个单词按照空格分开,并将每