详解Python循环作用域与闭包


Posted in Python onMarch 21, 2019

前言

首先来看一段代码

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原则

  1. L, local ? 在lambda函数内或者def函数内部的变量
  2. E, Enclosing-function ? 闭包的作用域
  3. G,Global ? 全局作用域
  4. 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循环作用域与闭包详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python中as用法实例分析
Apr 30 Python
pyqt5自定义信号实例解析
Jan 31 Python
python3 常见解密加密算法实例分析【base64、MD5等】
Dec 19 Python
tf.concat中axis的含义与使用详解
Feb 07 Python
Pycharm远程连接服务器并实现代码同步上传更新功能
Feb 25 Python
python+OpenCV实现图像拼接
Mar 05 Python
python 抓取知乎指定回答下视频的方法
Jul 09 Python
python连接mysql数据库并读取数据的实现
Sep 25 Python
Python爬虫之Selenium鼠标事件的实现
Dec 04 Python
Python操作PostgreSql数据库的方法(基本的增删改查)
Dec 29 Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 Python
PyTorch梯度裁剪避免训练loss nan的操作
May 24 Python
浅谈python之高阶函数和匿名函数
Mar 21 #Python
浅谈Python反射 & 单例模式
Mar 21 #Python
详解Python中is和==的区别
Mar 21 #Python
浅谈Python的条件判断语句if/else语句
Mar 21 #Python
python使用thrift教程的方法示例
Mar 21 #Python
在Python中如何传递任意数量的实参的示例代码
Mar 21 #Python
详解python使用turtle库来画一朵花
Mar 21 #Python
You might like
PHP错误和异常处理功能模块示例
2016/11/12 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
2017/06/11 PHP
三个思路解决laravel上传文件报错:413 Request Entity Too Large问题
2017/11/13 PHP
JavaScript 小型打飞机游戏实现原理说明
2010/10/28 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
jQuery+.net实现浏览更多内容(改编php版本)
2013/03/28 Javascript
Javascript四舍五入Math.round()与Math.pow()使用介绍
2013/12/27 Javascript
jquery制作 随机弹跳的小球特效
2015/02/01 Javascript
kindeditor编辑器点中图片滚动条往上顶的bug
2015/07/05 Javascript
使用canvas实现仿新浪微博头像截取上传功能
2015/09/02 Javascript
jQuery实现仿百度首页滑动伸缩展开的添加服务效果代码
2015/09/09 Javascript
jquery精度计算代码 jquery指定精确小数位
2017/02/06 Javascript
setTimeout函数的神奇使用
2017/02/26 Javascript
利用JavaScript对中文(汉字)进行排序实例详解
2017/06/18 Javascript
JavaScript箭头函数中的this详解
2019/06/19 Javascript
JS实现移动端点击按钮复制文本内容
2019/07/28 Javascript
vue中在vuex的actions中请求数据实例
2019/11/08 Javascript
[00:36]DOTA2上海特级锦标赛 Archon战队宣传片
2016/03/04 DOTA
[52:41]OG vs IG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/20 DOTA
[42:06]2019国际邀请赛全明星赛 8.23
2019/09/05 DOTA
python 装饰器功能以及函数参数使用介绍
2012/01/27 Python
Linux下使用python调用top命令获得CPU利用率
2015/03/10 Python
python通过pil模块获得图片exif信息的方法
2015/03/16 Python
Python安装Numpy和matplotlib的方法(推荐)
2017/11/02 Python
详解python的变量缓存机制
2021/01/24 Python
解决virtualenv -p python3 venv报错的问题
2021/02/05 Python
H5离线存储Manifest原理及使用
2020/04/28 HTML / CSS
Mankind美国/加拿大:英国领先的男士美容护发用品公司
2018/12/05 全球购物
入学申请自荐信范文
2014/02/26 职场文书
保护环境建议书100字
2014/05/13 职场文书
客运企业隐患排查工作方案
2014/06/06 职场文书
2014年学校体育工作总结
2014/12/08 职场文书
2015新年寄语(一句话)
2014/12/08 职场文书
生日答谢词
2015/01/05 职场文书
2015年出纳工作总结与计划
2015/05/18 职场文书
JavaScript的Set数据结构详解
2022/02/18 Javascript