详解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传递参数方式小结
Apr 17 Python
基于python实现的抓取腾讯视频所有电影的爬虫
Apr 22 Python
python操作 hbase 数据的方法
Dec 18 Python
python如何派生内置不可变类型并修改实例化行为
Mar 21 Python
Python实现计算圆周率π的值到任意位的方法示例
May 08 Python
使用Python监视指定目录下文件变更的方法
Oct 15 Python
Django2.1集成xadmin管理后台所遇到的错误集锦(填坑)
Dec 20 Python
在python plt图表中文字大小调节的方法
Jul 08 Python
Python使用qrcode二维码库生成二维码方法详解
Feb 17 Python
Django 解决上传文件时,request.FILES为空的问题
May 20 Python
python seaborn heatmap可视化相关性矩阵实例
Jun 03 Python
Python selenium的这三种等待方式一定要会!
Jun 10 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
dede3.1分页文字采集过滤规则详说(图文教程)续二
2007/04/03 PHP
php查找任何页面上的所有链接的方法
2013/12/03 PHP
兼容各大浏览器带关闭按钮的漂浮多组图片广告代码
2014/06/05 PHP
使用php方法curl抓取AJAX异步内容思路分析及代码分享
2014/08/25 PHP
php和editplus正则表达式去除空白行
2015/04/17 PHP
php图像处理函数imagecopyresampled用法详解
2016/12/02 PHP
PHP 根据key 给二维数组分组
2016/12/09 PHP
php使用include 和require引入文件的区别
2017/02/16 PHP
复制小说文本时出现的随机乱码的去除方法
2010/09/07 Javascript
JQuery里选择超链接的实现代码
2011/05/22 Javascript
jquery实现table鼠标经过变色代码
2013/09/25 Javascript
JavaScript中数据结构与算法(三):链表
2015/06/19 Javascript
原生js模拟淘宝购物车项目实战
2015/11/18 Javascript
jQuery实现简单的文件上传进度条效果
2020/03/26 Javascript
jquery计算出left和top,让一个div水平垂直居中的简单实例
2016/07/13 Javascript
Vue.js事件处理器与表单控件绑定详解
2017/03/20 Javascript
JS实现简易的图片拖拽排序实例代码
2017/06/09 Javascript
node文件上传功能简易实现代码
2017/06/16 Javascript
使用jquery+iframe做一个ajax上传效果(实例)
2017/08/24 jQuery
简述vue中的config配置
2018/01/23 Javascript
解决Vue2.x父组件与子组件之间的双向绑定问题
2018/03/06 Javascript
vue实现移动端悬浮窗效果
2018/12/01 Javascript
详解vue-cli项目在IE浏览器打开报错解决方法
2020/12/10 Vue.js
读写json中文ASCII乱码问题的解决方法
2016/11/05 Python
python如何把嵌套列表转变成普通列表
2018/03/20 Python
我就是这样学习Python中的列表
2019/06/02 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
给你一面国旗 教你用python画中国国旗
2019/09/24 Python
python实现复制文件到指定目录
2019/10/16 Python
解决Firefox下不支持outerHTML问题代码分享
2014/06/04 HTML / CSS
新加坡领先的时尚生活方式零售品牌:CHARLES & KEITH
2018/01/16 全球购物
安全生产检讨书
2014/01/21 职场文书
初中班干部工作总结
2015/08/10 职场文书
调解协议书范本
2016/03/21 职场文书
服务器SVN搭建图文安装过程
2022/06/21 Servers
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技