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标准库os.path包、glob包使用实例
Nov 25 Python
Python实现的随机森林算法与简单总结
Jan 30 Python
Python根据指定日期计算后n天,前n天是哪一天的方法
May 29 Python
Python数据持久化shelve模块用法分析
Jun 29 Python
对Python3.6 IDLE常用快捷键介绍
Jul 16 Python
python opencv实现旋转矩形框裁减功能
Jul 25 Python
Python XlsxWriter模块Chart类用法实例分析
Mar 11 Python
django框架面向对象ORM模型继承用法实例分析
Jul 29 Python
详解Python中的分支和循环结构
Feb 11 Python
python读取多层嵌套文件夹中的文件实例
Feb 27 Python
Python编程快速上手——strip()函数的正则表达式实现方法分析
Feb 29 Python
python实现控制台输出颜色
Mar 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 session_start()问题解疑(详细介绍)
2013/07/05 PHP
微信公众号开发之微信公共平台消息回复类实例
2014/11/14 PHP
PHP 芝麻信用接入的注意事项
2016/12/01 PHP
js change,propertychange,input事件小议
2011/12/20 Javascript
从URL中提取参数与将对象转换为URL查询参数的实现代码
2012/01/12 Javascript
ExtJS[Desktop]实现图标换行示例代码
2013/11/17 Javascript
JavaScript中的常见问题解决方法(乱码,IE缓存,代理)
2013/11/28 Javascript
node.js不得不说的12点内容
2014/07/14 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
2014/10/31 Javascript
基于javascript实现判断移动终端浏览器版本信息
2014/12/09 Javascript
JavaScript给url网址进行encode编码的方法
2015/03/18 Javascript
jQuery简单实现仿京东商城的左侧菜单效果代码
2015/09/09 Javascript
判断数组是否包含某个元素的js函数实现方法
2016/05/19 Javascript
javascript显示系统当前时间代码
2016/12/29 Javascript
微信小程序学习(4)-系统配置app.json详解
2017/01/12 Javascript
基于JavaScript实现焦点图轮播效果
2017/03/27 Javascript
删除table表格行的实例讲解
2017/09/21 Javascript
Vue不能检测到Object/Array更新的情况的解决
2018/06/26 Javascript
35个最好用的Vue开源库(史上最全)
2019/01/03 Javascript
vue中$nextTick的用法讲解
2019/01/17 Javascript
[47:18]完美世界DOTA2联赛循环赛 IO vs FTD BO2第一场 11.05
2020/11/06 DOTA
利用Python为iOS10生成图标和截屏
2016/09/24 Python
Python实现曲线点抽稀算法的示例
2017/10/12 Python
CentOS 6.5中安装Python 3.6.2的方法步骤
2017/12/03 Python
django初始化数据库的实例
2018/05/27 Python
pandas dataframe添加表格框线输出的方法
2019/02/08 Python
python selenium执行所有测试用例并生成报告的方法
2019/02/13 Python
python虚拟环境模块venv使用及示例
2020/03/04 Python
请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1
2015/07/16 面试题
传播学专业毕业生自荐信
2013/11/04 职场文书
创建无烟单位实施方案
2014/03/29 职场文书
高考标语大全
2014/06/05 职场文书
毕业实习自我鉴定范文2014
2014/09/26 职场文书
2014七年级班主任工作总结
2014/12/05 职场文书
乡镇科协工作总结2015
2015/05/19 职场文书
2015年医院科室工作总结范文
2015/05/26 职场文书