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 相关文章推荐
仅用50行Python代码实现一个简单的代理服务器
Apr 08 Python
Python pickle模块用法实例
Apr 14 Python
python编程开发之日期操作实例分析
Nov 13 Python
实例讲解Python中函数的调用与定义
Mar 14 Python
python中快速进行多个字符替换的方法小结
Dec 15 Python
详解Python map函数及Python map()函数的用法
Nov 16 Python
详解Django 中是否使用时区的区别
Jun 14 Python
python利用thrift服务读取hbase数据的方法
Dec 27 Python
Python 生成一个从0到n个数字的列表4种方法小结
Nov 28 Python
python:目标检测模型预测准确度计算方式(基于IoU)
Jan 18 Python
如何基于python对接钉钉并获取access_token
Apr 21 Python
基于django 的orm中非主键自增的实现方式
May 18 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 正则 过滤html 的超链接
2009/06/02 PHP
深入mysql_fetch_row()与mysql_fetch_array()的区别详解
2013/06/05 PHP
JQuery动态创建DOM、表单元素的实现代码
2011/08/09 Javascript
关于query Javascript CSS Selector engine
2013/04/12 Javascript
Egret引擎开发指南之视觉编程
2014/09/03 Javascript
跟我学习javascript的循环
2015/11/18 Javascript
简单对比分析JavaScript中的apply,call与this的使用
2015/12/04 Javascript
javascript拖拽应用实例(二)
2016/03/25 Javascript
最细致的vue.js基础语法 值得收藏!
2016/11/03 Javascript
pc加载更多功能和移动端下拉刷新加载数据
2016/11/07 Javascript
详解ES6之用let声明变量以及let loop机制
2017/07/15 Javascript
JS异步函数队列功能实例分析
2017/11/28 Javascript
详解vue+vuex+koa2开发环境搭建及示例开发
2018/01/22 Javascript
JS将时间秒转换成天小时分钟秒的字符串
2019/07/10 Javascript
原生js实现点击轮播切换图片
2020/02/11 Javascript
微信小程序去除左上角返回键的实现方法
2020/03/06 Javascript
[42:20]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
Pycharm技巧之代码跳转该如何回退
2017/07/16 Python
Python数据分析库pandas基本操作方法
2018/04/08 Python
python实现嵌套列表平铺的两种方法
2018/11/08 Python
python存储16bit和32bit图像的实例
2018/12/05 Python
Python中的字符串切片(截取字符串)的详解
2019/05/15 Python
python求解汉诺塔游戏
2020/07/09 Python
使用canvas绘制贝塞尔曲线
2014/12/17 HTML / CSS
越南综合购物网站:Lazada越南
2019/06/10 全球购物
乌克兰数字设备、配件和智能技术的连锁商店:KTC
2020/08/18 全球购物
德国便宜的宠物店:Brekz.de
2020/10/23 全球购物
医药大学生求职简历的自我评价
2013/10/17 职场文书
师范应届生求职信
2013/11/15 职场文书
化工专业大学生职业生涯规划书
2014/01/14 职场文书
棉花姑娘教学反思
2014/02/15 职场文书
学校2014年度工作总结
2014/12/06 职场文书
2014年防汛工作总结
2014/12/08 职场文书
晚会开幕词
2015/01/28 职场文书
调解协议书范本
2016/03/21 职场文书
python如何利用traceback获取详细的异常信息
2021/06/05 Python