详解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 查找文件夹下所有文件 实现代码
Jul 01 Python
python字典键值对的添加和遍历方法
Sep 11 Python
Python实现在线音乐播放器
Mar 03 Python
Python实现的破解字符串找茬游戏算法示例
Sep 25 Python
Python数据分析中Groupby用法之通过字典或Series进行分组的实例
Dec 08 Python
numpy返回array中元素的index方法
Jun 27 Python
Python对象转换为json的方法步骤
Apr 25 Python
python如何制作英文字典
Jun 25 Python
python之语音识别speech模块
Sep 09 Python
Python爬虫简单运用爬取代理IP的实现
Dec 01 Python
2021年最新用于图像处理的Python库总结
Jun 15 Python
Python+OpenCV实现在图像上绘制矩形
Mar 21 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的GD库imagettftext函数解决中文乱码问题
2015/01/24 PHP
PHP获取数组长度或某个值出现次数的方法
2015/02/11 PHP
PHP异步进程助手async-helper
2018/02/05 PHP
PHP实现的DES加密解密类定义与用法示例
2020/11/02 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
PHP读取文件,解决中文乱码UTF-8的方法分析
2020/01/22 PHP
js计数器代码
2006/11/04 Javascript
JavaScript监测ActiveX控件是否已经安装过的代码
2008/09/02 Javascript
IE网页js语法错误2行字符1、FF中正常的解决方法
2013/09/09 Javascript
jQuery 删除或是清空某个HTML元素示例
2014/08/04 Javascript
node.js中的fs.fchmodSync方法使用说明
2014/12/16 Javascript
Jquery实现图片预加载与延时加载的方法
2014/12/22 Javascript
jQuery实现tab选项卡效果的方法
2015/07/08 Javascript
原生js实现秒表计时器功能
2017/02/16 Javascript
Bootstrap Tree View简单而优雅的树结构组件实例解析
2017/06/15 Javascript
vue按需引入element Transfer 穿梭框
2017/09/30 Javascript
JavaScript模块模式实例详解
2017/10/25 Javascript
layui数据表格实现重载数据表格功能(搜索功能)
2019/07/27 Javascript
vue点击当前路由高亮小案例
2019/09/26 Javascript
[02:06]DOTA2肉山黑名单魔法终结者 敌法师中文配音鉴赏
2013/06/17 DOTA
详解Django通用视图中的函数包装
2015/07/21 Python
Python中标准库OS的常用方法总结大全
2017/07/19 Python
python实现黑客字幕雨效果
2018/06/21 Python
python实现linux下抓包并存库功能
2018/07/18 Python
python接口自动化之ConfigParser配置文件的使用详解
2020/08/03 Python
python与idea的集成的实现
2020/11/20 Python
python实现启动一个外部程序,并且不阻塞当前进程
2020/12/05 Python
详解使用CSS3的@media来编写响应式的页面
2017/11/01 HTML / CSS
家佳咖啡店创业计划书
2013/12/27 职场文书
运动会跳远广播稿
2014/02/04 职场文书
青年志愿者活动总结
2014/04/26 职场文书
政治思想表现评语
2014/05/04 职场文书
信用社主任竞聘演讲稿
2014/05/23 职场文书
如何用PHP实现分布算法之一致性哈希算法
2021/05/26 PHP
opencv-python图像配准(匹配和叠加)的实现
2021/06/23 Python
九大龙王魂骨,山龙王留下躯干骨,榜首死的最憋屈(被捏碎)
2022/03/18 国漫