Python闭包的两个注意事项(推荐)


Posted in Python onMarch 20, 2017

什么是闭包?

简单说,闭包就是根据不同的配置信息得到不同的结果。

再来看看专业的解释:闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

延迟绑定

Python闭包函数所引用的外部自由变量是延迟绑定的。

Python

In [2]: def multipliers():
  ...:   return [lambda x: i * x for i in range(4)] 
In [3]: print [m(2) for m in multipliers()]
[6, 6, 6, 6]
In [2]: def multipliers():
  ...:   return [lambda x: i * x for i in range(4)] 
In [3]: print [m(2) for m in multipliers()]
[6, 6, 6, 6]

如以上代码: i是闭包函数引用的外部作用域的自由变量, 只有在内部函数被调用的时候才会搜索变量i的值, 由于循环已结束, i指向最终值3, 所以各函数调用都得到了相同的结果。

解决方法:

1) 生成闭包函数的时候立即绑定(使用函数形参的默认值):

Python

In [5]: def multipliers():
  return [lambda x, i=i: i* x for i in range(4)]
    ...: 
In [6]: print [m(2) for m in multipliers()]
[0, 2, 4, 6]
In [5]: def multipliers():
  return [lambda x, i=i: i* x for i in range(4)]
    ...: 
In [6]: print [m(2) for m in multipliers()]
[0, 2, 4, 6]

如以上代码: 生成闭包函数的时候, 可以看到每个闭包函数都有一个带默认值的参数: i=i, 此时, 解释器会查找i的值, 并将其赋予形参i, 这样在生成闭包函数的外部作用域(即外部循环中), 找到了变量i, 遂将其当前值赋予形参i。

2) 使用functools.partial:

Python

In [26]: def multipliers():
  return [functools.partial(lambda i, x: x * i, i) for i in range(4)]
  ....: 
In [27]: print [m(2) for m in multipliers()]
  [0, 2, 4, 6]
In [26]: def multipliers():
  return [functools.partial(lambda i, x: x * i, i) for i in range(4)]
  ....: 
In [27]: print [m(2) for m in multipliers()]
  [0, 2, 4, 6]

如以上代码: 在有可能因为延迟绑定而出问题的时候, 可以通过functools.partial构造偏函数, 使得自由变量优先绑定到闭包函数上。

禁止在闭包函数内对引用的自由变量进行重新绑定

Python

def foo(func):
  free_value = 8
  def _wrapper(*args, **kwargs):
    old_free_value = free_value #保存旧的free_value
    free_value = old_free_value * 2 #模拟产生新的free_value
    func(*args, **kwargs)
    free_value = old_free_value
  return _wrapper
def foo(func):
  free_value = 8
  def _wrapper(*args, **kwargs):
    old_free_value = free_value #保存旧的free_value
    free_value = old_free_value * 2 #模拟产生新的free_value
    func(*args, **kwargs)
    free_value = old_free_value
  return _wrapper

以上代码会报错, UnboundLocalError: local variable 'free_value' referenced before assignment, 以上代码本意是打算实现一个带有某个初始化状态(free_value)但在执行内部闭包函数的时候又可以按需变化出新的状态(free_value = old_free_value * 2)的装饰器, 但内部由于发生了重新绑定, 解释器会将free_value看作局部变量, old_free_value = free_value则会报错, 因为解释器认为free_value是没有赋值就被引用了。

解决:

打算修改闭包函数引用的自由变量时, 可以将其放入一个list, 这样, free_value = [8], free_value不可修改, 但free_value[0]是可以安全的被修改的。

另外, Python 3.x增加了nonlocal关键字, 也可以解决这个问题。

以上所述是小编给大家介绍的Python闭包的两个注意事项,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python机器学习之贝叶斯分类
Mar 26 Python
Django如何自定义分页
Sep 25 Python
python版飞机大战代码分享
Nov 20 Python
使用Python控制摄像头拍照并发邮件
Apr 23 Python
Django基础三之视图函数的使用方法
Jul 18 Python
Python 通过截图匹配原图中的位置(opencv)实例
Aug 27 Python
Python+OpenCV实现旋转文本校正方式
Jan 09 Python
python输出pdf文档的实例
Feb 13 Python
Python定时任务APScheduler原理及实例解析
May 30 Python
FP-growth算法发现频繁项集——构建FP树
Jun 24 Python
Pygame Draw绘图函数的具体使用
Nov 17 Python
python对文档中元素删除,替换操作
Apr 02 Python
使用python实现生成用户信息
Mar 20 #Python
Unicode和Python的中文处理
Mar 19 #Python
Android 兼容性问题:java.lang.UnsupportedOperationException解决办法
Mar 19 #Python
Python 专题三 字符串的基础知识
Mar 19 #Python
关于python的bottle框架跨域请求报错问题的处理方法
Mar 19 #Python
Python 专题二 条件语句和循环语句的基础知识
Mar 19 #Python
解决Python requests 报错方法集锦
Mar 19 #Python
You might like
PHP 5.3 下载时 VC9、VC6、Thread Safe、Non Thread Safe的区别分析
2011/03/28 PHP
PHP实现把文本中的URL转换为链接的auolink()函数分享
2014/07/29 PHP
使用PHP如何实现高效安全的ftp服务器(二)
2015/12/30 PHP
ThinkPHP连接Oracle数据库
2016/04/22 PHP
浅析PHP反序列化中过滤函数使用不当导致的对象注入问题
2020/02/15 PHP
javascript新手语法小结
2008/06/15 Javascript
扩展js对象数组的OrderByAsc和OrderByDesc方法实现思路
2013/05/17 Javascript
jQuery图片滚动图片的效果(另类实现)
2013/06/02 Javascript
javascript页面上使用动态时间具体实现
2014/03/18 Javascript
jquery实现当滑动到一定位置时固定效果
2014/06/17 Javascript
nodejs中使用monk访问mongodb
2014/07/06 NodeJs
浅谈JavaScript中定义变量时有无var声明的区别
2014/08/18 Javascript
微信小程序 教程之wxapp 视图容器 view
2016/10/19 Javascript
JS动态的把左边列表添加到右边的实现代码(可上下移动)
2016/11/17 Javascript
vue keep-alive请求数据的方法示例
2018/05/16 Javascript
点击按钮弹出模态框的一系列操作代码实例
2019/03/29 Javascript
对Layer UI 模块化的用法详解
2019/09/26 Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
2020/05/24 Javascript
JavaScript文档加载模式以及元素获取
2020/07/28 Javascript
[07:12]2014DOTA2西雅图国际邀请赛 黑马Liquid专题采访
2014/07/12 DOTA
[01:01:14]完美世界DOTA2联赛PWL S2 SZ vs Rebirth 第一场 11.21
2020/11/23 DOTA
Python调用命令行进度条的方法
2015/05/05 Python
Python自定义进程池实例分析【生产者、消费者模型问题】
2016/09/19 Python
Python实现的堆排序算法示例
2018/04/29 Python
python中如何使用分步式进程计算详解
2019/03/22 Python
python协程gevent案例 爬取斗鱼图片过程解析
2019/08/27 Python
python线程信号量semaphore使用解析
2019/11/30 Python
python 如何把docker-compose.yaml导入到数据库相关条目里
2021/01/15 Python
CSS3轻松实现圆角效果
2017/11/09 HTML / CSS
html5读取本地文件示例代码
2014/04/22 HTML / CSS
Servlet如何得到客户端机器的信息
2014/10/17 面试题
房产委托公证书样本
2014/04/04 职场文书
导师推荐信范文
2014/05/09 职场文书
班级出游活动计划书
2014/08/15 职场文书
思想品德课教学反思
2016/02/24 职场文书
八年级作文之一起的走过日子
2019/09/17 职场文书