详解Python循环作用域与闭包
作者:震灵 发布时间:2023-01-28 20:34:30
前言
首先来看一段代码
x_list = [i for i in range(30)]
y_list = [i for i in range(10, 20)]
for y in y_list:
x_list = filter(lambda a: a != y, x_list)
x_list = list(x_list)
print(x_list)
print(len(x_list))
这段代码会输出什么呢?
正确答案是一个长度为29的List。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
29
但是实际上,上述代码我们想要表达的意图是从x_list中剔除所有在y_list中的元素。为什么在实际情况下,最终只会剔除一个元素呢?这主要与Python的作用域机制有关。
Python作用域机制
Python与其他语言不同,Python没有循环作用域这个说法。Python的作用域遵循LEGB原则
L, local – 在lambda函数内或者def函数内部的变量
E, Enclosing-function – 闭包的作用域
G,Global – 全局作用域
B, Build-in – 内建作用域
为了证明Python没有循环作用域,可以通过下面一段代码验证
for i in range(10):
pass
print(i)
运行代码,发现可以正常运行,运行结果i==9。由此可以证明Python不存在循环作用域,循环变量属于全局作用域。
基于上述结论,就可以很好地说明为什么上述的filter函数最终只去掉了一个元素。
因为filter函数是一个惰性函数,因此在循环过程中并不会进行实际运算,而当循环完成,需要实际输出的时候,此时全局作用域环境下的i已经变为了一个固定值19,因此最终只有19可以从x_list中去掉。
解决方案——闭包
面对上述问题,我们有两个解决方案。
第一个解决方案——避免惰性求值。可以发现,问题的根源在于filter函数是一个惰性求值函数,因此造成了这个问题。可以通过强制求值运算,强制每一次循环都进行filter操作,从而实现正常的筛选操作。代码如下所示。
x_list = [i for i in range(30)]
y_list = [i for i in range(10, 20)]
for y in y_list:
x_list = list(filter(lambda a: a != y, x_list))
x_list = list(x_list)
print(x_list)
print(len(x_list))
第二个解决方案——闭包。有时候我们不想放弃惰性求值这个特性,那么我们就需要引入更高级的函数式编程思想——闭包。
因为Python支持函数式编程语法,可以将函数作为变量,因此可以很容易的实现闭包特性。
x_list = [i for i in range(30)]
y_list = [i for i in range(10, 20)]
def check(a, b):
print('check')
return a != b
for y in y_list:
def x_filter(y):
global x_list
x_list = filter(lambda x: check(x, y), x_list)
x_filter(y)
print('loop')
x_list = list(x_list)
print(x_list)
print(len(x_list))
上面的代码为了证明惰性求值的有效性,因此稍微繁琐了一些。在实际场景中,check函数可以直接写成lambda函数的形式。
闭包之所以能解决循环作用域问题,是因为闭包有独立的作用域。因此即便是惰性求值,但是由于闭包作用于已经将临时变量进行了存储,因此依然可以正确进行筛选操作。
总结
Python与其他编程语言不同,不存在循环临时作用域,因此在某些场景下会出现与其它编程语言结果不一致的BUG。面对这种情况,我们一般可以通过两种方式来解决
1.避免惰性求值
2.使用闭包来保存循环临时变量
以上所述是小编给大家介绍的Python循环作用域与闭包详解整合网站的支持!
来源:https://www.imooc.com/article/282963
猜你喜欢
- 按理说unittest 中是不应该测试那种外部依赖很强的用例,但是呢,有时候有些接口总是调试好之后怕忘了,就写了一些简单的测试case,想要
- 1.正则表达式是什么很简单就是一种字符串匹配,eg: 比如你在注册账户时我们需要对用户的用户名判断是否合法,这时候就需要对用户输入的检索,或
- 希尔排序希尔排序是一个叫希尔的数学家提出的一种优化版本的插入排序。首先取一个整数d1=n//2,将元素分为d1个组,每组相邻元素之间的距离为
- XmlDocume
- 如何显示一个文本文件?完整显示文本文件的代码如下: Write(STRING) WriteLine(STRING) WriteBlan
- 导语日常开发中,定位程序异常,追溯事件发生场景都需要通过日志记录的方式。可以说一个好的开发日志设计可以让开发人员在后续项目维护的过程中节省时
- 本文实例为大家分享了python多线程分块读取文件的具体代码,供大家参考,具体内容如下# _*_coding:utf-8_*_import
- 原因是:It looks like you need to flush stdout periodically (e.g. sys.stdo
- 这篇文档所给出的编码约定适用于在主要的Python发布版本中组成标准库的Python 代码,请查阅相关的关
- 我们的网络协议一般是把数据转换成JSON之后再传输。之前在Java里面,实现序列化和反序列化,不管是 jackson ,还是 fastjso
- 什么是LSTM1、LSTM的结构我们可以看出,在n时刻,LSTM的输入有三个:当前时刻网络的输入值Xt;上一时刻LSTM的输出值ht-1;上
- 语言是信息传播的主要障碍。多语言网站,顾名思义就是能够以多种语言(而不是单种语言)为用户提供信息服务,让使用不同语言的用户都能够从同个网站获
- 目录1图像叠加2图像融合3按位操作1图像叠加可以通过OpenCV函数cv.add()或简单地通过numpy操作添加两个图像,res = im
- Mysql分页采用limt关键字select * from t_order limit 5,10; #返回第6-15行数据select *
- infer 这个关键字,整理记录一下,避免后面忘记了。有点难以理解呢。inferinfer 是在 typescript 2.8中新增的关键字
- 一、PIL库对图像的基本操作1、读取图片PIL网上有很多介绍,这里不再讲解。直接操作,读取一张图片,将其转换为灰度图像,并打印出来。from
- 文章主要描述的是SQL Server聚集索引的指示(Cluster Index Indications),在实际操作中借助聚集索引来进行搜索
- Python jieba分词如何添加自定义词和去除不需要长尾词通过如下代码,读取一个txt的高频词汇:# 找到高频词汇 &nb
- 1. 介绍前面我们尝试通过python实现了代码雨以及字母随机闪烁的效果,这次,我们再来实现一个代码的线性扫面。同样的,此次我们仍然是使用3
- 代码如下:Set Catalog_object= Server.CreateObject("ADO