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 19 Python
利用Opencv中Houghline方法实现直线检测
Feb 11 Python
Window环境下Scrapy开发环境搭建
Nov 18 Python
scrapy-redis的安装部署步骤讲解
Feb 27 Python
Python简单I/O操作示例
Mar 18 Python
简单了解python 邮件模块的使用方法
Jul 24 Python
django中的数据库迁移的实现
Mar 16 Python
python小程序基于Jupyter实现天气查询的方法
Mar 27 Python
基于python检查矩阵计算结果
May 21 Python
Python 在局部变量域中执行代码
Aug 07 Python
python logging模块的使用详解
Oct 23 Python
详解基于Facecognition+Opencv快速搭建人脸识别及跟踪应用
Jan 21 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三元运算符的结合性介绍
2012/01/10 PHP
PHP实现WebService的简单示例和实现步骤
2015/03/27 PHP
PHP实现无限级分类(不使用递归)
2015/10/22 PHP
微信支付开发订单查询实例
2016/07/12 PHP
laravel 解决crontab不执行的问题
2019/10/22 PHP
用JavaScript脚本实现Web页面信息交互
2006/12/21 Javascript
jQuery中:only-child选择器用法实例
2015/01/03 Javascript
推荐一款jQuery插件模板
2015/01/09 Javascript
详解jquery事件delegate()的使用方法
2016/01/25 Javascript
Bootstrap多级导航栏(级联导航)的实现代码
2016/03/08 Javascript
js使用Replace结合正则替换重复出现的字符串功能示例
2016/12/27 Javascript
ReactJs实现树形结构的数据显示的组件的示例
2017/08/18 Javascript
jQuery访问浏览器本地存储cookie、localStorage和sessionStorage的基本用法
2017/10/20 jQuery
vue项目每30秒刷新1次接口的实现方法
2018/12/04 Javascript
微信小程序使用自定义组件导航实现当前页面高亮
2020/01/02 Javascript
基于JavaScript实现十五拼图代码实例
2020/04/26 Javascript
[04:14]从西雅图到上海——玩家自制DOTA2主题歌曲应援TI9
2019/07/11 DOTA
python实现2048小游戏
2015/03/30 Python
Python中的下划线详解
2015/06/24 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
Python3.5内置模块之time与datetime模块用法实例分析
2019/04/27 Python
Python3网络爬虫中的requests高级用法详解
2019/06/18 Python
python @classmethod 的使用场合详解
2019/08/23 Python
CSS3 :not()选择器实现最后一行li去除某种css样式
2016/10/19 HTML / CSS
css3新单位vw、vh的使用教程
2018/03/23 HTML / CSS
基于HTML5 audio元素播放声音jQuery小插件
2011/05/11 HTML / CSS
美国球鞋寄卖网站:Stadium Goods
2018/05/09 全球购物
自考生自我评价分享
2014/01/18 职场文书
小学教师师德师风个人整改措施
2014/09/18 职场文书
2014年社区教育工作总结
2014/12/02 职场文书
受资助学生感谢信
2015/01/21 职场文书
作弊检讨书范文
2015/05/06 职场文书
高中地理教学反思
2016/02/19 职场文书
导游词之秦皇岛燕塞湖
2020/01/03 职场文书
还在手动盖楼抽奖?教你用Python实现自动评论盖楼抽奖(一)
2021/06/07 Python
Python中的 Set 与 dict
2022/03/13 Python