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写的一个简单DNS服务器实例
Jun 04 Python
Python读写文件方法总结
Jun 09 Python
Python argv用法详解
Jan 08 Python
python 内置函数filter
Jun 01 Python
Python多进程multiprocessing用法实例分析
Aug 18 Python
python导出chrome书签到markdown文件的实例代码
Dec 27 Python
Python实现去除列表中重复元素的方法总结【7种方法】
Feb 16 Python
Python中的self用法详解
Aug 06 Python
python安装scipy的步骤解析
Sep 28 Python
Python django搭建layui提交表单,表格,图标的实例
Nov 18 Python
Python如何绘制日历图和热力图
Aug 07 Python
总结几个非常实用的Python库
Jun 26 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源代码加密?PHP二进制加密与解密的解决办法
2013/04/22 PHP
PHP写日志的实现方法
2014/11/05 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
PHP实现简单的模板引擎功能示例
2017/09/02 PHP
解决php用mysql方式连接数据库出现Deprecated报错问题
2019/12/25 PHP
PHP接入支付宝接口失效流程详解
2020/11/10 PHP
jQuery each()方法的使用方法
2010/03/18 Javascript
js实现按一下删除键删除整个单词附demo
2014/09/05 Javascript
jQuery与getJson结合的用法实例
2015/08/07 Javascript
jquery实现简单文字提示效果
2015/12/02 Javascript
js简单设置与使用cookie的方法
2016/01/22 Javascript
JS使用正则表达式实现关键字替换加粗功能示例
2016/08/03 Javascript
Bootstrap导航条学习使用(二)
2017/02/08 Javascript
Javarscript中模块(module)、加载(load)与捆绑(bundle)详解
2017/05/28 Javascript
AngularJS 打开新的标签页实现代码
2017/09/07 Javascript
js实现百度淘宝搜索功能
2020/02/17 Javascript
Vue 请求传公共参数的操作
2020/07/31 Javascript
python实现向微信用户发送每日一句 python实现微信聊天机器人
2019/03/27 Python
Python 实现数据结构-堆栈和队列的操作方法
2019/07/17 Python
关于Numpy数据类型对象(dtype)使用详解
2019/11/27 Python
python时间与Unix时间戳相互转换方法详解
2020/02/13 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
python3中编码获取网页的实例方法
2020/11/16 Python
python中K-means算法基础知识点
2021/01/25 Python
会计电算化应届生求职信
2013/11/03 职场文书
活动总结模板
2014/05/09 职场文书
细节决定成败演讲稿
2014/05/12 职场文书
银行主办会计岗位职责
2014/08/13 职场文书
社区关爱留守儿童活动方案
2014/08/22 职场文书
刑事代理授权委托书
2014/09/17 职场文书
机关干部三严三实心得体会
2014/10/13 职场文书
2014年幼儿园安全工作总结
2014/11/10 职场文书
绿色环保倡议书
2015/04/28 职场文书
思品教学工作总结
2015/08/10 职场文书
教学反思怎么写
2016/02/24 职场文书
vue实现可以快进后退的跑马灯组件
2022/04/08 Vue.js