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使用函数默认值实现函数静态变量的方法
Aug 18 Python
教你用Python脚本快速为iOS10生成图标和截屏
Sep 22 Python
浅谈Python Opencv中gamma变换的使用详解
Apr 02 Python
解决python 输出是省略号的问题
Apr 19 Python
对numpy中数组转置的求解以及向量内积计算方法
Oct 31 Python
pytorch实现保证每次运行使用的随机数都相同
Feb 20 Python
解决python多线程报错:AttributeError: Can't pickle local object问题
Apr 08 Python
pycharm的python_stubs问题
Apr 08 Python
小 200 行 Python 代码制作一个换脸程序
May 12 Python
解决Python 写文件报错TypeError的问题
Oct 23 Python
python爬虫利用代理池更换IP的方法步骤
Feb 21 Python
python实现MD5进行文件去重的示例代码
Jul 09 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电台频率大全 - 22 重庆市
2020/03/11 无线电
一些关于PHP的知识
2006/11/17 PHP
PHP Zip压缩 在线对文件进行压缩的函数
2010/05/26 PHP
PHP里的中文变量说明
2011/07/23 PHP
php计算程序运行时间的简单例子分享
2014/05/10 PHP
php中stdClass的用法分析
2015/02/27 PHP
分享php邮件管理器源码
2016/01/06 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
Javascript中的this绑定介绍
2011/09/22 Javascript
JQuery 操作/获取table具体代码
2013/06/13 Javascript
JS对文本框值的判断示例
2014/03/10 Javascript
jquery利用拖拽方式在图片上添加热链接
2015/11/24 Javascript
JavaScript事件学习小结(三)js事件对象
2016/06/09 Javascript
Knockout结合Bootstrap创建动态UI实现产品列表管理
2016/09/14 Javascript
针对后台列表table拖拽比较实用的jquery拖动排序
2016/10/10 Javascript
jQuery插件HighCharts实现的2D条状图效果示例【附demo源码下载】
2017/03/15 Javascript
vue中用动态组件实现选项卡切换效果
2017/03/25 Javascript
使用 NodeJS+Express 开发服务端的简单介绍
2017/04/07 NodeJs
jQuery Masonry瀑布流布局神器使用详解
2017/05/25 jQuery
Angular2.0实现modal对话框的方法示例
2018/02/18 Javascript
Vue中使用Sortable的示例代码
2018/04/07 Javascript
使用webpack4编译并压缩ES6代码的方法示例
2019/04/24 Javascript
基于layui轮播图满屏是高度自适应的解决方法
2019/09/16 Javascript
微信小程序实现下拉加载更多商品
2020/12/29 Javascript
python 接收处理外带的参数方法
2018/12/03 Python
python使用wxpy实现微信消息防撤回脚本
2019/04/29 Python
纯CSS3实现图片无间断轮播效果
2016/08/25 HTML / CSS
css3绘制百度的小度熊
2018/10/29 HTML / CSS
详解CSS3中border-image的使用
2015/07/18 HTML / CSS
汽车运用工程毕业生自荐信
2013/10/29 职场文书
党校毕业心得体会
2014/09/13 职场文书
企业务虚会发言材料
2014/10/20 职场文书
公司奖励通知
2015/04/21 职场文书
学校教学管理制度
2015/08/06 职场文书
MySQL 数据库范式化设计理论
2022/04/22 MySQL
Java中Dijkstra(迪杰斯特拉)算法
2022/05/20 Java/Android