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 参数列表中的self 显式不等于冗余
Dec 01 Python
Scrapy的简单使用教程
Oct 24 Python
Python实现按特定格式对文件进行读写的方法示例
Nov 30 Python
正则给header的冒号两边参数添加单引号(Python请求用)
Aug 09 Python
python将字母转化为数字实例方法
Oct 04 Python
django多种支付、并发订单处理实例代码
Dec 13 Python
在python3中实现更新界面
Feb 21 Python
Python常用数据分析模块原理解析
Jul 20 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
Jul 28 Python
Python基于template实现字符串替换
Nov 27 Python
Python实现淘宝秒杀功能的示例代码
Jan 19 Python
python绘制简单直方图(质量分布图)的方法
Apr 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迅雷、快车、旋风下载专用链转换代码
2010/06/15 PHP
php bootstrap实现简单登录
2016/03/08 PHP
2017年最好用的9个php开发工具推荐(超好用)
2017/10/23 PHP
Nigma vs AM BO3 第一场2.13
2021/03/10 DOTA
autoIMG 基于jquery的图片自适应插件代码
2011/03/12 Javascript
jQuery使用动态渲染表单功能完成ajax文件下载
2013/01/15 Javascript
JS获取地址栏参数的几种方法小结
2014/02/28 Javascript
js实现仿QQ秀换装效果的方法
2015/03/04 Javascript
jQuery+css3实现Ajax点击后动态删除功能的方法
2015/08/10 Javascript
javascript中日期函数new Date()的浏览器兼容性问题
2015/09/05 Javascript
JavaScript实现类似淘宝的购物车效果
2017/03/16 Javascript
nodejs前端自动化构建环境的搭建
2017/07/26 NodeJs
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
JS+CSS实现滚动数字时钟效果
2017/12/25 Javascript
微信小程序动态生成二维码的实现代码
2018/07/25 Javascript
JS数组索引检测中的数据类型问题详解
2021/01/11 Javascript
用python实现的可以拷贝或剪切一个文件列表中的所有文件
2009/04/30 Python
python登录QQ邮箱发信的实现代码
2013/02/10 Python
Using Django with GAE Python 后台抓取多个网站的页面全文
2016/02/17 Python
python实现数据导出到excel的示例--普通格式
2018/05/03 Python
解决python3 pika之连接断开的问题
2018/12/18 Python
在Python中Dataframe通过print输出多行时显示省略号的实例
2018/12/22 Python
python计算二维矩形IOU实例
2020/01/18 Python
TensorFlow tf.nn.softmax_cross_entropy_with_logits的用法
2020/04/19 Python
keras 模型参数,模型保存,中间结果输出操作
2020/07/06 Python
Python设计密码强度校验程序
2020/07/30 Python
解决python和pycharm安装gmpy2 出现ERROR的问题
2020/08/28 Python
python 实现音频叠加的示例
2020/10/29 Python
HTML5+CSS设置浮动却没有动反而在中间且错行的问题
2020/05/26 HTML / CSS
美丽的珠宝配饰:SmallThings
2019/09/04 全球购物
明星员工获奖感言
2014/08/14 职场文书
2015年预备党员自我评价
2015/03/04 职场文书
煤矿安全生产工作总结
2015/08/13 职场文书
Spring中bean的生命周期之getSingleton方法
2021/06/30 Java/Android
Python初识逻辑与if语句及用法大全
2021/08/07 Python
德生BCL3000抢先使用感受和评价
2022/04/07 无线电