热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

什么是闭包?关于python闭包的两个问题解决办法

闭包就是根据不同的配置信息得到不同的结果。下面通过本文给大家分享Python闭包的两个注意事项,需要的朋友参考下
闭包就是根据不同的配置信息得到不同的结果。下面通过本文给大家分享Python闭包的两个注意事项,需要的朋友参考下

什么是闭包?

简单说,闭包就是根据不同的配置信息得到不同的结果。

再来看看专业的解释:闭包(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关键字, 也可以解决这个问题。


推荐阅读
  • 2023年,Android开发前景如何?25岁还能转行吗?
    近期,关于Android开发行业的讨论在多个平台上热度不减,许多人担忧其未来发展。本文将探讨当前Android开发市场的现状、薪资水平及职业选择建议。 ... [详细]
  • 软件测试行业深度解析:迈向高薪的必经之路
    本文深入探讨了软件测试行业的发展现状及未来趋势,旨在帮助有志于在该领域取得高薪的技术人员明确职业方向和发展路径。 ... [详细]
  • 黑客组织NB65公开泄露俄罗斯实体信息
    近日,黑客组织NB65宣布泄露了一系列与俄罗斯相关的实体数据,引起广泛关注。 ... [详细]
  • 在日常生活中,支付宝已成为不可或缺的支付工具之一。本文将详细介绍如何通过支付宝实现免费提现,帮助用户更好地管理个人财务,避免不必要的手续费支出。 ... [详细]
  • 如何在PyCharm中配置Python脚本的默认模板
    本文介绍如何在PyCharm中设置Python脚本的默认模板,以便每次创建新的.py文件时自动填充预设内容,提高开发效率。 ... [详细]
  • 解决Word文档无法打开的问题
    本文探讨了Word文档无法正常打开的原因及解决方案,包括病毒感染和模板损坏等常见问题。 ... [详细]
  • 本项目分为七个主要阶段,包括项目启动、现状评估、风险管理、体系文件编写、体系发布与试运行、体系认证审核及项目收尾。每个阶段都设定了明确的任务和目标,以确保ISMS(信息安全管理体系)的有效实施。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 理财规划:迈向财务自由的路径
    实现财务自由,摆脱经济压力,是许多人的梦想。财务自由不仅意味着有足够的财富支持生活,还包括能够灵活应对未来可能遇到的各种经济挑战。本文将探讨如何通过有效的理财规划达到这一目标。 ... [详细]
  • 本文介绍了SELinux的两种主要工作模式——强制模式和宽容模式,并提供了如何在CentOS 7中正确启用和配置SELinux的方法,以及在遇到登录问题时的解决策略。 ... [详细]
  • 调试利器SSH隧道
    在开发微信公众号或小程序的时候,由于微信平台规则的限制,部分接口需要通过线上域名才能正常访问。但我们一般都会在本地开发,因为这能快速的看到 ... [详细]
  • 了解多域名SAN SSL证书及其工作原理
    本文介绍了多域名SAN SSL证书的概念及其工作方式,探讨其在现代网络安全中的重要性和应用。 ... [详细]
  • 龙蜥社区开发者访谈:技术生涯的三次蜕变 | 第3期
    龙蜥社区的开发者们通过自己的实践和经验,推动着开源技术的发展。本期「龙蜥开发者说」聚焦于一位资深开发者的三次技术转型,分享他在龙蜥社区的成长故事。 ... [详细]
  • 最新版 EasyCriteria 3.0 已正式上线,该版本经过全面重构,带来了多项性能优化与功能增强。更多详情请参阅官方文档:http://uaihebert.com/?p=1898 ... [详细]
  • 解决PHP项目在服务器无法抓取远程网页内容的问题
    本文探讨了在使用PHP进行后端开发时,遇到的一个常见问题:即在本地环境中能够正常通过CURL获取远程网页内容,但在服务器上却无法实现。我们将分析可能的原因并提供解决方案。 ... [详细]
author-avatar
城哥_1986
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有