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局域网ip扫描示例分享
Apr 03 Python
python使用opencv进行人脸识别
Apr 07 Python
Python机器学习库scikit-learn安装与基本使用教程
Jun 25 Python
pandas.DataFrame选取/排除特定行的方法
Jul 03 Python
TensorFlow Session会话控制&Variable变量详解
Jul 30 Python
django富文本编辑器的实现示例
Apr 10 Python
Python学习笔记之变量、自定义函数用法示例
May 28 Python
解决pycharm 工具栏Tool中找不到Run manager.py Task的问题
Jul 01 Python
python下载库的步骤方法
Oct 12 Python
python判断链表是否有环的实例代码
Jan 31 Python
django 数据库 get_or_create函数返回值是tuple的问题
May 15 Python
python绘制箱型图
Apr 27 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
新浪SAE云平台下使用codeigniter的数据库配置
2014/06/12 PHP
PHP的PDO操作简单示例
2016/03/30 PHP
非常实用的php验证码类
2016/05/15 PHP
PHP判断文件是否被引入的方法get_included_files用法示例
2016/11/29 PHP
PHP+Ajax实现的博客文章添加类别功能示例
2018/03/29 PHP
javaScript对象和属性的创建方法
2007/01/15 Javascript
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
2011/12/20 Javascript
jquery改变tr背景色的示例代码
2013/12/28 Javascript
jQuery之ajax删除详解
2014/02/27 Javascript
jQuery过滤选择器:not()方法使用介绍
2014/04/20 Javascript
node.js中的url.resolve方法使用说明
2014/12/10 Javascript
node.js cookie-parser 中间件介绍
2016/06/06 Javascript
js阻止冒泡和默认事件(默认行为)详解
2016/10/20 Javascript
bootstrap 点击空白处popover弹出框隐藏实例
2018/01/24 Javascript
javaScript中"=="和"==="的区别详解
2018/03/16 Javascript
浅谈使用mpvue开发小程序需要注意和了解的知识点
2018/05/23 Javascript
实例详解ztree在vue项目中使用并且带有搜索功能
2018/08/24 Javascript
解决vue打包css文件中背景图片的路径问题
2018/09/03 Javascript
js的继承方法小结(prototype、call、apply)(推荐)
2019/04/17 Javascript
原生js实现分页效果
2020/09/23 Javascript
JavaScript本地储存:localStorage、sessionStorage、cookie的使用
2020/10/13 Javascript
[02:37]TI8勇士令状不朽珍藏II视频展示
2018/06/23 DOTA
python创建线程示例
2014/05/06 Python
python实现在windows服务中新建进程的方法
2015/06/30 Python
Python使用爬虫抓取美女图片并保存到本地的方法【测试可用】
2018/08/30 Python
python使用PIL模块获取图片像素点的方法
2019/01/08 Python
numpy数组广播的机制
2019/07/12 Python
土耳其时尚购物网站:Morhipo
2017/09/04 全球购物
瑞典时尚服装购物网站:Miinto.se
2017/10/30 全球购物
澳大利亚玩具剧场:Toy Playhouse
2019/03/03 全球购物
如何选择使用结构还是类
2014/05/30 面试题
勾股定理课后反思
2014/04/26 职场文书
党员承诺书格式
2014/05/21 职场文书
安全生产宣传标语
2014/06/06 职场文书
会计试用期自我评价
2014/09/19 职场文书
党员教师个人对照检查材料范文
2014/09/25 职场文书