详解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中的包和模块实例
Nov 22 Python
老生常谈python之鸭子类和多态
Jun 13 Python
Python实现读取TXT文件数据并存进内置数据库SQLite3的方法
Aug 08 Python
Python3 Random模块代码详解
Dec 04 Python
详解python中的装饰器
Jul 10 Python
如何利用Anaconda配置简单的Python环境
Jun 24 Python
python中使用while循环的实例
Aug 05 Python
python多项式拟合之np.polyfit 和 np.polyld详解
Feb 18 Python
浅谈django channels 路由误导
May 28 Python
Python过滤掉numpy.array中非nan数据实例
Jun 08 Python
Django 用户认证Auth组件的使用
Nov 30 Python
在 Python 中使用 7zip 备份文件的操作
Dec 11 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面向对象——访问修饰符介绍
2012/11/08 PHP
php数据库备份还原类分享
2014/03/20 PHP
php让json_encode不自动转义斜杠“/”的方法
2020/04/27 PHP
jquery.validate使用攻略 第三部
2010/07/01 Javascript
Js组件的一些写法
2010/09/10 Javascript
jquery解决图片路径不存在执行替换路径
2013/02/06 Javascript
JavaScript字符串对象fromCharCode方法入门实例(用于把Unicode值转换为字符串)
2014/10/17 Javascript
javascript中的this详解
2014/12/08 Javascript
node.js中的buffer.copy方法使用说明
2014/12/14 Javascript
JS排序方法(sort,bubble,select,insert)代码汇总
2016/01/30 Javascript
浅谈js中的in-for循环
2016/06/28 Javascript
轻松实现js弹框显示选项
2016/09/13 Javascript
基于jquery实现多选下拉列表
2017/08/02 jQuery
JavaScript图片处理与合成总结
2018/03/04 Javascript
vue单个组件实现无限层级多选菜单功能
2018/04/10 Javascript
Vue侦测相关api的实现方法
2019/05/22 Javascript
你了解vue3.0响应式数据怎么实现吗
2019/06/07 Javascript
Vue编程式跳转的实例代码详解
2019/07/10 Javascript
js实现盒子拖拽动画效果
2020/08/09 Javascript
python的绘图工具matplotlib使用实例
2014/07/03 Python
在Python中操作时间之tzset()方法的使用教程
2015/05/22 Python
python实用代码片段收集贴
2015/06/03 Python
用python写的一个wordpress的采集程序
2016/02/27 Python
opencv python 2D直方图的示例代码
2018/07/20 Python
Python 正则表达式匹配字符串中的http链接方法
2018/12/25 Python
Python同时处理多个异常的方法
2020/07/28 Python
详解Python3.8+PyQt5+pyqt5-tools+Pycharm配置详细教程
2020/11/02 Python
Python如何使用神经网络进行简单文本分类
2021/02/25 Python
CSS3 按钮边框动画的实现
2020/11/12 HTML / CSS
农村改厕实施方案
2014/03/22 职场文书
毕业生求职信范文
2014/06/29 职场文书
违反单位工作制度检讨书
2014/10/25 职场文书
iPhone13将有八大升级
2021/04/15 数码科技
Golang中interface{}转为数组的操作
2021/04/30 Golang
Python办公自动化之Excel(中)
2021/05/24 Python
Python测试框架pytest高阶用法全面详解
2022/06/01 Python