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脚本对Linux服务器进行监控的教程
Apr 02 Python
python获得linux下所有挂载点(mount points)的方法
Apr 29 Python
Python3中类、模块、错误与异常、文件的简易教程
Nov 20 Python
Python paramiko模块的使用示例
Apr 11 Python
Python实现的简单计算器功能详解
Aug 25 Python
python自动化测试之DDT数据驱动的实现代码
Jul 23 Python
python如何保证输入键入数字的方法
Aug 23 Python
Python通过递归获取目录下指定文件代码实例
Nov 07 Python
在 Python 中接管键盘中断信号的实现方法
Feb 04 Python
Keras中 ImageDataGenerator函数的参数用法
Jul 03 Python
python 获取字典特定值对应的键的实现
Sep 29 Python
Python实现随机爬山算法
Jan 29 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
全国FM电台频率大全 - 18 湖南省
2020/03/11 无线电
如何开始收听短波广播
2021/03/01 无线电
PHP 实例化类的一点摘记
2008/03/23 PHP
php中修改浏览器的User-Agent来伪装你的浏览器和操作系统
2011/07/29 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十二)
2014/06/25 PHP
PHP数组与对象之间使用递归实现转换的方法
2015/06/24 PHP
通过jquery还原含有rowspan、colspan的table的实现方法
2012/02/10 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
jquery选择器-根据多个属性选择示例代码
2013/10/21 Javascript
JS脚本defer的作用示例介绍
2014/01/02 Javascript
js和jquery实现监听键盘事件示例代码
2020/06/24 Javascript
常用的JQuery函数及功能小结
2016/03/24 Javascript
jQuery+ajax实现滚动到页面底部自动加载图文列表效果(类似图片懒加载)
2016/06/07 Javascript
VueJs与ReactJS和AngularJS的异同点
2016/12/12 Javascript
vue.js指令和组件详细介绍及实例
2017/04/06 Javascript
利用forever和pm2部署node.js项目过程
2017/05/10 Javascript
AngularJS中下拉框的高级用法示例
2017/10/11 Javascript
详解jquery和vue对比
2019/04/16 jQuery
electron-vue开发环境内存泄漏问题汇总
2019/10/10 Javascript
[39:11]DOTA2上海特级锦标赛C组资格赛#2 LGD VS Newbee第二局
2016/02/28 DOTA
python使用点操作符访问字典(dict)数据的方法
2015/03/16 Python
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
django实现分页的方法
2015/05/26 Python
Python数据结构之单链表详解
2017/09/12 Python
Python实现扣除个人税后的工资计算器示例
2018/03/26 Python
解决在pycharm中显示额外的 figure 窗口问题
2019/01/15 Python
浅谈python编译pyc工程--导包问题解决
2019/03/20 Python
详解python 内存优化
2020/08/17 Python
Python利用socket模块开发简单的端口扫描工具的实现
2021/01/27 Python
美国领先的奢侈手表在线零售商:WatchMaxx
2017/12/17 全球购物
在浏览器端如何得到服务器端响应的XML数据
2012/11/24 面试题
2013年高中生自我评价
2013/10/23 职场文书
优秀研究生自我鉴定
2013/12/04 职场文书
学术会议通知范文
2015/04/15 职场文书
只用Python就可以制作的简单词云
2021/06/07 Python
解决spring.thymeleaf.cache=false不起作用的问题
2022/06/10 Java/Android