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实现读取目录所有文件的文件名并保存到txt文件代码
Nov 22 Python
Python简单调用MySQL存储过程并获得返回值的方法
Jul 20 Python
Python 实现链表实例代码
Apr 07 Python
使用Python对Csv文件操作实例代码
May 12 Python
Python数据分析之如何利用pandas查询数据示例代码
Sep 01 Python
python 实现判断ip连通性的方法总结
Apr 22 Python
pandas 透视表中文字段排序方法
Nov 16 Python
python是否适合网页编程详解
Oct 04 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
Oct 21 Python
Tensorflow训练模型越来越慢的2种解决方案
Feb 07 Python
Python类成员继承重写的实现
Sep 16 Python
Python使用PyYAML库读写yaml文件的方法
Apr 06 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
追忆往昔!浅谈收音机的百年发展历史
2021/03/01 无线电
第十节--抽象方法和抽象类
2006/11/16 PHP
PHP+MYSQL实现用户的增删改查
2015/03/24 PHP
php导出中文内容excel文件类实例
2015/07/06 PHP
PHP CURL中传递cookie的方法步骤
2019/05/09 PHP
Thinkphp5框架中引入Markdown编辑器操作示例
2020/06/03 PHP
JavaScript中的对象化编程
2008/01/16 Javascript
Exjs 入门篇
2010/04/07 Javascript
jquery中this的使用说明
2010/09/06 Javascript
JS target与currentTarget区别说明
2011/08/28 Javascript
20款效果非常棒的 jQuery 插件小结分享
2011/11/18 Javascript
运算符&&的三个不同层次
2013/04/07 Javascript
利用javaScript实现点击输入框弹出窗体选择信息
2013/12/11 Javascript
button没写type=button会导致点击时提交
2014/03/06 Javascript
window.location.href IE下跳转失效的解决方法
2014/03/27 Javascript
教你用jquery实现iframe自适应高度
2014/06/11 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
Bootstrap进度条组件知识详解
2016/05/01 Javascript
JS中的hasOwnProperty()和isPrototypeOf()属性实例详解
2016/08/11 Javascript
简单学习vue指令directive
2016/11/03 Javascript
bootstrap的工具提示实例代码
2017/05/17 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
深入浅析ES6 Class 中的 super 关键字
2017/10/20 Javascript
Vue 实现展开折叠效果的示例代码
2018/08/27 Javascript
thinkjs微信中控之微信鉴权登陆的实现代码
2019/08/08 Javascript
记录vue做微信自定义分享的一些问题
2019/09/12 Javascript
详解Python中dict与set的使用
2015/08/10 Python
Python RabbitMQ消息队列实现rpc
2018/05/30 Python
Python 变量的创建过程详解
2019/09/02 Python
浅谈Tensorflow 动态双向RNN的输出问题
2020/01/20 Python
html5 利用canvas实现超级玛丽简单动画
2013/09/06 HTML / CSS
Spartoo荷兰:鞋子、包包和服装
2018/07/12 全球购物
公司人力资源的自我评价
2014/01/02 职场文书
离婚协议书范本2014
2014/10/27 职场文书
2014年后勤工作总结范文
2014/12/16 职场文书
小学四年级作文之写景
2019/08/23 职场文书