Python中的闭包

本文作者:黎智煊,叩丁狼高级讲师。原创文章,转载请注明出处。

什么是闭包?闭包有什么用?为什么要用闭包?今天我们就带着这3个问题来一步一步认识闭包。闭包和函数紧密联系在一起,介绍闭包前有必要先介绍一些背景知识,诸如嵌套函数、变量的作用域等概念

  1. 作用域

    作用域是程序运行时变量可被访问的范围,定义在函数内的变量是局部变量,局部变量的作用范围只能是函数内部范围内,它不能在函数外引用。

    def foo():
    num = 10 # 局部变量
    print(num)  # NameError: name 'num' is not defined
    
    

    定义在模块最外层的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的。例如:

    num = 10 # 全局变量
    def foo():
    print(num)  # 10
    
    
  2. 嵌套函数

    函数不仅可以定义在模块的最外层,还可以定义在另外一个函数的内部,像这种定义在函数里面的函数称之为嵌套函数(nested function)例如:

    def print_msg():
     # print_msg 是外围函数
     msg = "zen of python"
    
     def printer():
         # printer是嵌套函数
         print(msg)
     printer()
    # 输出 zen of python
    print_msg()
    
    

    对于嵌套函数,它可以访问到其外层作用域中声明的非局部(non-local)变量,比如代码示例中的变量 msg 可以被嵌套函数 printer 正常访问。

那么有没有一种可能即使脱离了函数本身的作用范围,局部变量还可以被访问得到呢?答案是闭包

什么是闭包

函数身为第一类对象,它可以作为函数的返回值返回,现在我们来考虑如下的例子:

def print_msg():
    # print_msg 是外围函数
    msg = "zen of python"
    def printer():
        # printer 是嵌套函数
        print(msg)
    return printer

another = print_msg()
# 输出 zen of python
another()

这段代码和前面例子的效果完全一样,同样输出 “zen of python”。不同的地方在于内部函数 printer 直接作为返回值返回了。

一般情况下,函数中的局部变量仅在函数的执行期间可用,一旦 print_msg() 执行过后,我们会认为 msg变量将不再可用。然而,在这里我们发现 print_msg 执行完之后,在调用 another 的时候 msg 变量的值正常输出了,这就是闭包的作用,闭包使得局部变量在函数外被访问成为可能。

为什么要使用闭包

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子:

def adder(x):
    def wrapper(y):
        return x + y
    return wrapper

adder5 = adder(5)
# 输出 15
adder5(10)
# 输出 11
adder5(6)

这比用类来实现更优雅,此外装饰器也是基于闭包的一中应用场景。

所有函数都有一个 closure属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell 对象 组成的元组对象。cell 对象的cell_contents 属性就是闭包中的自由变量。

>>> adder.__closure__
>>> adder5.__closure__
(<cell at 0x103075910: int object at 0x7fd251604518>,)
>>> adder5.__closure__[0].cell_contents
5

这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell_contents中了。

想获取更多技术视频,请前往叩丁狼官网:http://www.wolfcode.cn/openClassWeb_listDetail.html

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 什么是闭包?闭包有什么用?为什么要用闭包?今天我们就带着这3个问题来一步一步认识闭包。 闭包和函数紧密联系在一起,...
    码农小杨阅读 413评论 0 2
  • 这两天学习的时候对python中的闭包产生了兴趣,网上这篇文章写得很好,写在这里大家看看。 1. 闭包的概念 首...
    Alistair阅读 311评论 0 0
  • 目录 作用域(scope) 闭包的定义 闭包的作用 总结 2018.4.15更新了对于函数作用域的理解内容 1.作...
    苦逼李阅读 782评论 1 0
  • 导读:Python中的装饰器经常用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。本文从闭包的概念...
    zgjx阅读 473评论 0 3
  • (一) 我不希望你因我而变, 更不希望你对我一成不变。 (二) 有的人愿意为爱而疯狂, 我更喜欢安宁直到天黑。 (...
    紫色领结阅读 761评论 2 5

友情链接更多精彩内容