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中实现贪婪排名算法的教程
Apr 17 Python
PyMongo安装使用笔记
Apr 27 Python
Python中处理字符串之endswith()方法的使用简介
May 18 Python
Python3搜索及替换文件中文本的方法
May 22 Python
[原创]教女朋友学Python(一)运行环境搭建
Nov 29 Python
python K近邻算法的kd树实现
Sep 06 Python
win10系统下Anaconda3安装配置方法图文教程
Sep 19 Python
pycharm恢复默认设置或者是替换pycharm的解释器实例
Oct 29 Python
使用python绘制温度变化雷达图
Oct 18 Python
通过实例了解python property属性
Nov 01 Python
在Python IDLE 下调用anaconda中的库教程
Mar 09 Python
python基于socket模拟实现ssh远程执行命令
Dec 05 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
codeigniter实现get分页的方法
2015/07/10 PHP
鼠标滚轮控制网页横向移动实现思路
2013/03/22 Javascript
JavaScript中的style.cssText使用教程
2014/11/06 Javascript
浅析Javascript中“==”与“===”的区别
2014/12/23 Javascript
JS中用try catch对代码运行的性能影响分析
2016/12/26 Javascript
详解Vue整合axios的实例代码
2017/06/21 Javascript
JavaScript简介_动力节点Java学院整理
2017/06/26 Javascript
详解React Native 采用Fetch方式发送跨域POST请求
2017/11/15 Javascript
Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决
2018/01/27 Javascript
基于JS实现前端压缩上传图片的实例代码
2019/05/14 Javascript
laypage+SpringMVC实现后端分页
2019/07/27 Javascript
no-vnc和node.js实现web远程桌面的完整步骤
2019/08/11 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
2019/09/25 Javascript
[38:21]2014 DOTA2国际邀请赛中国区预选赛5.21 TongFu VS LGD-CDEC
2014/05/22 DOTA
[01:44]Ti10举办地公布
2019/08/25 DOTA
Python环境下安装使用异步任务队列包Celery的基础教程
2016/05/07 Python
利用python爬取散文网的文章实例教程
2017/06/18 Python
python自定义异常实例详解
2017/07/11 Python
Python基于递归和非递归算法求两个数最大公约数、最小公倍数示例
2018/05/21 Python
python构建基础的爬虫教学
2018/12/23 Python
Django中的用户身份验证示例详解
2019/08/07 Python
python基于opencv检测程序运行效率
2019/12/28 Python
Python使用循环神经网络解决文本分类问题的方法详解
2020/01/16 Python
python圣诞树编写实例详解
2020/02/13 Python
Python与C/C++的相互调用案例
2021/03/04 Python
火山动力Java笔试题
2014/06/26 面试题
科室工作个人总结的自我评价
2013/10/29 职场文书
大学自我鉴定范文
2013/12/26 职场文书
《登鹳雀楼》教学反思
2014/04/09 职场文书
幼儿园教师演讲稿
2014/05/06 职场文书
入党转正申请报告
2015/05/15 职场文书
晚会开幕词范文
2016/03/04 职场文书
2016年清明节网上祭英烈活动总结
2016/04/01 职场文书
公开致歉信
2019/06/24 职场文书
python中的class_static的@classmethod的巧妙用法
2021/06/22 Python
不想升级Win11?教你彻底锁定老版Windows系统的方法(附下载地址)
2022/09/23 数码科技