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 Web开发模板引擎优缺点总结
May 06 Python
python生成指定尺寸缩略图的示例
May 07 Python
python实现周期方波信号频谱图
Jul 21 Python
Python3enumrate和range对比及示例详解
Jul 13 Python
Python:slice与indices的用法
Nov 25 Python
Python实现变声器功能(萝莉音御姐音)
Dec 05 Python
python3 动态模块导入与全局变量使用实例
Dec 22 Python
Python 程序员必须掌握的日志记录
Aug 17 Python
详解Anaconda 的安装教程
Sep 23 Python
scrapy-redis分布式爬虫的搭建过程(理论篇)
Sep 29 Python
全网最全python库selenium自动化使用详细教程
Jan 12 Python
用Python的绘图库(matplotlib)绘制小波能量谱
Apr 17 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保留两位小数并且四舍五入及不四舍五入的方法
2013/09/22 PHP
Linux编译升级php的详细方法
2013/11/04 PHP
php中smarty变量修饰用法实例分析
2015/06/11 PHP
php微信公众平台开发之微信群发信息
2016/09/13 PHP
javascript中的变量是传值还是传址的?
2010/04/19 Javascript
textarea中的手动换行处理的jquery代码
2011/02/26 Javascript
html组件不可输入(只读)同时任何组件都有效
2013/04/01 Javascript
解析JavaScript中instanceof对于不同的构造器或许都返回true
2013/12/03 Javascript
jQuery的缓存机制浅析
2014/06/07 Javascript
javascript实现表格排序 编辑 拖拽 缩放
2015/01/02 Javascript
js表单元素checked、radio被选中的几种方法(详解)
2016/08/22 Javascript
JavaScript数组_动力节点Java学院整理
2017/06/26 Javascript
NodeJs form-data格式传输文件的方法
2017/12/13 NodeJs
Angular2 父子组件通信方式的示例
2018/01/29 Javascript
vue中子组件传递数据给父组件的讲解
2019/01/27 Javascript
深入理解vue中的slot与slot-scope
2019/04/22 Javascript
详解VUE项目中安装和使用vant组件
2019/04/28 Javascript
jQuery实现图片下载代码
2019/07/18 jQuery
vue实现路由不变的情况下,刷新页面操作示例
2020/02/02 Javascript
Vue组件化开发之通用型弹出框的实现
2020/02/28 Javascript
彻底搞懂并解决vue-cli4中图片显示的问题实现
2020/08/31 Javascript
[01:02:04]EG vs Liquid 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
Python正则表达式使用范例分享
2016/12/04 Python
pandas 使用apply同时处理两列数据的方法
2018/04/20 Python
TensorFlow 多元函数的极值实例
2020/02/10 Python
使用phonegap检测网络状态的方法
2017/03/30 HTML / CSS
美国批发零售网站:GearXS
2016/07/26 全球购物
耐克美国官网:Nike.com
2016/08/01 全球购物
美国鲜花递送:UrbanStems
2021/01/04 全球购物
大学生职业规划论文
2014/01/11 职场文书
中央空调节能方案
2014/06/15 职场文书
课外小组活动总结
2014/08/27 职场文书
防火标语大全
2014/10/06 职场文书
2016春节慰问信范文
2015/03/25 职场文书
求职自我评价参考范文
2019/05/16 职场文书
Python3 使用pip安装git并获取Yahoo金融数据的操作
2021/04/08 Python