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文件扩展名和文件名方法
Feb 02 Python
Python 装饰器实现DRY(不重复代码)原则
Mar 05 Python
Python3用tkinter和PIL实现看图工具
Jun 21 Python
python判断设备是否联网的方法
Jun 29 Python
django 发送邮件和缓存的实现代码
Jul 18 Python
Python中的函数式编程:不可变的数据结构
Oct 08 Python
python 常见字符串与函数的用法详解
Nov 23 Python
Flask框架学习笔记之表单基础介绍与表单提交方式
Aug 12 Python
Python协程操作之gevent(yield阻塞,greenlet),协程实现多任务(有规律的交替协作执行)用法详解
Oct 14 Python
Pycharm和Idea支持的vim插件的方法
Feb 21 Python
新手入门学习python Numpy基础操作
Mar 02 Python
Python 面向对象部分知识点小结
Mar 09 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执行速度全攻略(下)
2006/10/09 PHP
php的curl实现get和post的代码
2008/08/23 PHP
PHP下对字符串的递增运算代码
2010/08/21 PHP
php下批量挂马和批量清马代码
2011/02/27 PHP
PHP中3种生成XML文件方法的速度效率比较
2012/10/06 PHP
PHP中设置时区,记录日志文件的实现代码
2013/01/07 PHP
php实现在限定区域里自动调整字体大小的类实例
2015/04/02 PHP
phpMyAdmin安装并配置允许空密码登录
2015/07/04 PHP
PHP实现的最大正向匹配算法示例
2017/12/19 PHP
关于实现代码语法标亮 dp.SyntaxHighlighter
2007/02/02 Javascript
JAVASCRIPT keycode总结
2009/02/04 Javascript
javascript 设置某DIV区域内的checkbox复选框
2009/11/30 Javascript
jquery怎样实现ajax联动框(一)
2013/03/08 Javascript
jQuery的live()方法对hover事件的处理示例
2014/02/27 Javascript
Node.js中HTTP模块与事件模块详解
2014/11/14 Javascript
angular.extend方法的具体使用
2017/09/14 Javascript
微信小程序之数据缓存的实例详解
2017/09/29 Javascript
基于ionic实现下拉刷新功能
2018/05/10 Javascript
在vue项目中,将juery设置为全局变量的方法
2018/09/25 Javascript
node使用Mongoose类库实现简单的增删改查
2018/11/08 Javascript
Vue 中获取当前时间并实时刷新的实现代码
2020/05/12 Javascript
Vue中强制组件重新渲染的正确方法
2021/01/03 Vue.js
Python算法之栈(stack)的实现
2014/08/18 Python
python获取磁盘号下盘符步骤详解
2019/06/19 Python
详解Python是如何实现issubclass的
2019/07/24 Python
python实现PCA降维的示例详解
2020/02/24 Python
python 爬取免费简历模板网站的示例
2020/09/27 Python
结构和类有什么异同
2012/07/16 面试题
军训自我鉴定200字
2014/02/13 职场文书
写给老师的感谢信
2015/01/20 职场文书
委托书英文
2015/01/28 职场文书
岗位职责范本大全
2015/02/26 职场文书
酒店宣传语大全
2015/07/13 职场文书
经典格言警句:没有热忱,世间便无进步
2019/11/13 职场文书
Apache Hudi的多版本清理服务彻底讲解
2022/03/31 Servers
微信小程序 WeUI扩展组件库的入门教程
2022/04/21 Javascript