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函数参数*args**kwargs用法实例
Dec 04 Python
Python字符串详细介绍
May 09 Python
Python下的Softmax回归函数的实现方法(推荐)
Jan 26 Python
Python进阶之递归函数的用法及其示例
Jan 31 Python
pycharm使用matplotlib.pyplot不显示图形的解决方法
Oct 28 Python
使用tensorflow实现VGG网络,训练mnist数据集方式
May 26 Python
python操作微信自动发消息的实现(微信聊天机器人)
Jul 14 Python
matplotlib 三维图表绘制方法简介
Sep 20 Python
Django实现随机图形验证码的示例
Oct 15 Python
关于Python3的import问题(pycharm可以运行命令行import错误)
Nov 18 Python
python 实现图与图之间的间距调整subplots_adjust
May 21 Python
Python中常见的反爬机制及其破解方法总结
Jun 10 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
重置版宣传动画
2020/04/09 魔兽争霸
PHP学习之PHP变量
2006/10/09 PHP
PHP记录搜索引擎蜘蛛访问网站足迹的方法
2015/04/15 PHP
php实现的任意进制互转类分享
2015/07/07 PHP
php根据日期显示所在星座的方法
2015/07/13 PHP
浅谈使用PHP开发微信支付的流程
2015/10/04 PHP
Linux服务器下PHPMailer发送邮件失败的问题解决
2017/03/04 PHP
PHP基于cookie实现统计在线人数功能示例
2019/01/16 PHP
javascript 触发HTML元素绑定的函数
2010/09/11 Javascript
深入理解Ajax的get和post请求
2016/06/02 Javascript
JS Array创建及concat()split()slice()的使用方法
2016/06/03 Javascript
vue下跨域设置的相关介绍
2017/08/26 Javascript
如何为vue的项目添加单元测试
2018/12/19 Javascript
layuiAdmin循环遍历展示商品图片列表的方法
2019/09/16 Javascript
jquery实现鼠标悬浮弹出气泡提示框
2020/12/23 jQuery
Python中利用sqrt()方法进行平方根计算的教程
2015/05/15 Python
Python列表和元组的定义与使用操作示例
2017/07/26 Python
PYQT5实现控制台显示功能的方法
2019/06/25 Python
简单了解python PEP的一些知识
2019/07/13 Python
Django rest framework jwt的使用方法详解
2019/08/08 Python
TensorFlow 读取CSV数据的实例
2020/02/05 Python
Python如何对XML 解析
2020/06/28 Python
python中的垃圾回收(GC)机制
2020/09/21 Python
python多线程爬取西刺代理的示例代码
2021/01/30 Python
10分钟理解CSS3 FlexBox弹性布局
2018/12/20 HTML / CSS
New Balance英国官方网站:始于1906年,百年慢跑品牌
2016/12/07 全球购物
美国复古街头服饰精品店:Need Supply Co.
2017/02/22 全球购物
亚马逊西班牙购物网站:amazon西班牙
2017/03/06 全球购物
美国棒球装备和用品商店:Baseball Savings
2018/06/09 全球购物
四查四看剖析材料
2014/02/14 职场文书
生物科学专业自荐书
2014/06/20 职场文书
搞笑婚礼主持词开场白
2015/11/24 职场文书
CSS3实现的水平标题菜单
2021/04/14 HTML / CSS
如何解决.cuda()加载用时很长的问题
2021/05/24 Python
JavaScript数组 几个常用方法总结
2021/11/11 Javascript
Alexa停服!网站排名将何去何从?目前还没有替代品。
2022/04/15 杂记