背景

本文尝试介绍Python中的闭包(closure),包括闭包是什么? 为什么要使用闭包?如何使用闭包?

嵌套函数及非局部变量

在介绍闭包之前,需要先明白什么是嵌套函数和非局部变量。在一个函数(fun1)中定义的另一个函数(fun2)称为嵌套函数。嵌套函数(fun1)可以访问外围作用域的变量,即为非局部变量。换一句话说,嵌套函数能够访问enclosing scope(闭包作用域,或者外围作用域,或者外层作用域)下的变量。这些非局部变量默认情况下是只读的,为了修改它们,必须显式地将它们声明为非局部变量(使用nonlocal关键字)。具体示例如下:

    def print_msg(msg):# 这是外层函数def printer():# 这是嵌套函数print(msg)printer()# 调用外层函数print_msg("Hello World")

输出:

Hello World

可以看出,嵌套函数printer()是可以访问到非局部变量msg,即外层函数中的msg

定义一个闭包函数

如果上述示例print_msg()函数的最后一行不是调用printer(),而是返回printer呢?具体代码改成如下:

    def print_msg(msg):def printer():# 这是一个嵌套函数print(msg)return printer  # 返回嵌套函数# Now let's try calling this function.# 输出: Hello Worldanother = print_msg("Hello World")another()

可以看出输出结果是:

Hello World

这里调用print_msg()函数的时候传入了字符串Hello World,返回函数名为another。在调用another()时,之前传入的字符串Hello World信息仍然保留,尽管我们已经完成了print_msg()函数的执行。

这种将一些数据(比如上述示例中的Hello World)附加到代码中的技术在Python中称为闭包。enclosing scope中的会被存储,即使该变量超出作用域,或者函数本身被从当前命名空间中删除,也会记住外围作用域中的这个值。比如:

del print_msg
another()

依然能够输出:

Hello World

此时尝试调用:

print_msg("Hello")

报错如下:

File "test.py", line 306, in <module>print_msg("Hello World")
NameError: name 'print_msg' is not defined

因为返回函数仍然可以正常工作,而原始的函数已经被删除,无法像之前那样起作用。

什么是闭包

正如上面的例子所示,当嵌套函数在其外围作用域中引用一个值时,就出现了一个闭包。在Python中创建闭包,须满足的条件总结如下:

  • 必须有一个嵌套函数(函数中有函数)
  • 嵌套函数必须引用外围函数中定义的值
  • 外围函数必须返回嵌套函数

什么时候使用闭包

闭包可以避免使用全局变量,并提供某种形式的数据隐藏。它还可以为这个问题提供一个面向对象的解决方案。当类中需要实现的方法很少(大多数情况下只有一个方法)时,闭包可以提供一种替代的、更优雅的解决方案。但是,当属性和方法的数量比较多时,最好实现一个类。

下面是一个简单的例子,闭包可能比定义类和创建对象更合适。

def make_multiplier_of(n):def multiplier(x):return x * nreturn multiplier# Multiplier of 3
times3 = make_multiplier_of(3)# Multiplier of 5
times5 = make_multiplier_of(5)# 输出: 27
print(times3(9))# 输出: 15
print(times5(3))# 输出: 30
print(times5(times3(2)))

另外,需要注意的是:闭包函数中包含的值是可以找到的。所有的函数对象都有__closure__属性。当是闭包函数时,该属性返回cell objects的元组。以上述示例进行说明,其中times3times5都是闭包函数,打印输出:

print(make_multiplier_of.__closure__)
print(times3.__closure__)

输出结果如下:

None
(<cell at 0x7f5c8d8cb618: int object at 0xa68b00>,)

cell对象中的属性cell_contents存储着闭包值:

print(times3.__closure__[0].cell_contents)
print(times5.__closure__[0].cell_contents)

输出结果如下:

3
5

python中的闭包(closure)相关推荐

  1. Python 中的闭包、匿名函数、decorator 装饰器与python的偏函数

    Python中的闭包 def calc_sum(lst):def lazy_sum():return sum(lst)return lazy_sum 像这种内层函数引用了外层函数的变量(参数也算变量) ...

  2. python闭包的应用场景_简单谈谈Python中的闭包

    Python中的闭包 前几天又有人留言,关于其中一个闭包和re.sub的使用不太清楚.我在脚本之家搜索了下,发现没有写过闭包相关的东西,所以决定总结一下,完善Python的内容. 1. 闭包的概念 首 ...

  3. 什么是闭包及Python中的闭包

    什么是闭包 Objects are data with methods attached. Closures are functions with data attached. 一般来说,我们都非常熟 ...

  4. python代码:闭包closure的一个例子

    python代码:闭包closure的一个例子 #!/usr/bin/python # -*- coding: UTF-8 -*- """ @author: @file: ...

  5. Python中的闭包

    (如转载,请注明出处,谢谢.) 闭包这个概念在很多语言中都有涉及,本文主要谈谈python中的闭包.Python中使用闭包主要是在进行函数式开发时使用. 一,定义 python中的闭包从表现形式上定义 ...

  6. Python 中的闭包介绍

    引言 闭包是优雅的 Python 结构.在本文中,我们将了解它们,如何定义闭包,为什么以及何时使用它们. 但是在讨论什么是闭包之前,我们必须首先理解什么是嵌套函数,以及作用域规则是如何为它们工作的.那 ...

  7. Python中的闭包总结

    前几天又有人在我的这篇文章 python项目练习一:即时标记 下留言,关于其中一个闭包和re.sub的使用不太清楚.我在自己的博客上搜索了下,发现没有写过闭包相关的东西,所以决定总结一下,完善博客上P ...

  8. python有什么作用-Python中的闭包到底有什么用

    1.global关键字的作用 如果在函数中需要修改全局变量,则需要使用该关键字,具体参见下面例子. variable=100 deffunction():print(variable) #在函数内不对 ...

  9. javascript中的闭包closure详解

    文章目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一 ...

最新文章

  1. RedirectToAction()转移方式及参数传递
  2. docker镜像制作(二)——构建企业镜像LAMP+BBS
  3. P4770:你的名字(SAM、线段树合并)
  4. windows 导入表(动态调用)
  5. int** 赋值_一篇文章搞明白Integer、new Integer() 和 int 的概念与区别
  6. php td复制剪贴板,选择一个带有Javascript的完整表格(复制到剪贴板)
  7. vue 指令 v-model
  8. java泛型函数类型推断_为什么javac可以推断用作参数的函数的泛型类型参数?
  9. python语言-Python语言的一些基本常用语句
  10. 信息系统项目管理师 第二章 信息系统项目管理基础 核心知识点总结
  11. win10不让桌面上显示宽带连接服务器,Win10宽带连接桌面看不见了怎么办?
  12. 汽车技术管理系统c语言,[源码和文档分享]基于C语言实现的汽车牌照的快速查询...
  13. 浅谈PCA到PCANet
  14. IOS系统通话录音功能的实现方案
  15. 淘宝天猫京东拼多多抖音苏宁1688等平台关键词监控价格API接口(店铺商品价格监控API接口调用展示)
  16. 8086逻辑移位指令SHL和SHR
  17. 情感驿站 | 人生若是修行路,红尘处处皆道场
  18. ArcMap制图技巧之还原真实植被
  19. 安卓 LayoutInflater详解
  20. 设计模式读书笔记1-概述

热门文章

  1. nvidia平台重新安装sdkmanager运行不生效问题
  2. SAAS系统架构之成熟度模型
  3. 物联网的主要分为几个层次,主要有什么作用?
  4. 涂鸦WIFI模组方案(MCU SDK)
  5. elasticsearch系列三:索引详解(分词器、文档管理、路由详解(集群))
  6. 2014--2015年工作总结
  7. 第二章 射线与物质的相互作用----重带电粒子+电子+正电子+光子+中子
  8. ccf-csp历年满分题解 + 总结汇总(已完成55题,持续更新中...)
  9. cm60消费机说明书_中控CM50、CM60消费机二次开发SDK
  10. [开源福利] FreeRedis 历时两年正式发布 v1.0 [C#.NET Redis Client]