详解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访问mysql数据库的实现方法(2则示例)
Jan 06 Python
分享python数据统计的一些小技巧
Jul 21 Python
python fabric实现远程部署
Jan 05 Python
Python编程之string相关操作实例详解
Jul 22 Python
对Python subprocess.Popen子进程管道阻塞详解
Oct 29 Python
Python3.8中使用f-strings调试
May 22 Python
python turtle库画一个方格和圆实例
Jun 27 Python
Python 200行代码实现一个滑动验证码过程详解
Jul 11 Python
Python3 批量扫描端口的例子
Jul 25 Python
Tensorflow卷积实现原理+手写python代码实现卷积教程
May 22 Python
python实现excel公式格式化的示例代码
Dec 23 Python
利用python查看数组中的所有元素是否相同
Jan 08 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/01/10 PHP
UCenter 批量添加用户的php代码
2012/07/17 PHP
php fsockopen解决办法 php实现多线程
2014/01/20 PHP
php中文字符串截取方法实例总结
2014/09/30 PHP
php生成curl命令行的方法
2015/12/14 PHP
PHP基于mcript扩展实现对称加密功能示例
2019/02/21 PHP
IE无法设置短域名下Cookie
2010/09/23 Javascript
什么是DOM(Document Object Model)文档对象模型
2012/03/05 Javascript
JavaScript高级程序设计 阅读笔记(十七) js事件
2012/08/14 Javascript
js跨浏览器实现将字符串转化为xml对象的方法
2013/09/25 Javascript
js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
2016/04/01 Javascript
详解JavaScript的闭包、IIFE、apply、函数与对象
2016/12/21 Javascript
vue-cli构建项目使用 less的方法
2017/10/04 Javascript
Vue中的基础过渡动画及实现原理解析
2018/12/04 Javascript
浅谈js闭包理解
2019/03/28 Javascript
微信小程序配置服务器提示验证token失败的解决方法
2019/04/03 Javascript
Vue中通过Vue.extend动态创建实例的方法
2019/08/13 Javascript
浅析webpack-bundle-analyzer在vue-cli3中的使用
2019/10/23 Javascript
vue学习笔记之slot插槽基本用法实例分析
2020/02/01 Javascript
使用JS实现鼠标放上图片进行放大离开实现缩小功能
2021/01/27 Javascript
[05:24]TI9采访——教练
2019/08/24 DOTA
Python自定义类的数组排序实现代码
2016/08/28 Python
Python WSGI的深入理解
2018/08/01 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
2018/10/30 Python
Python+Kepler.gl实现时间轮播地图过程解析
2020/07/20 Python
HTML5拖放效果的实现代码
2016/11/17 HTML / CSS
伦敦高级内衣品牌:Agent Provocateur(大内密探)
2016/08/23 全球购物
Turnbull & Asser官网:英国皇室御用的顶级定制衬衫
2019/01/31 全球购物
英国网上超市:Ocado
2020/03/05 全球购物
学校与家长安全责任书
2014/07/23 职场文书
2014公司党员自我评价范文
2014/09/11 职场文书
试用期工作表现自我评价
2015/03/06 职场文书
2015年城管个人工作总结范文
2015/04/20 职场文书
微信小程序实现拍照和相册选取图片
2021/05/09 Javascript
实现一个简单得数据响应系统
2021/11/11 Javascript
使用ICOM IC-R9500接收机同时测评十台收音机中波接收性能
2022/05/10 无线电