• Python 闭包


    什么是闭包?

    闭包(closure)是词法闭包(lexical closure)的简称。闭包不是新奇的概念,而是早在高级程序语言开始发展的年代就已产生。

    对闭包的理解大致分为两类,将闭包视为函数或者是由函数及其引用环境组成的复合体。

    1. 前者认为闭包是在其词法上下文中引用了自动变量的函数。
    2. 后者认为闭包是显示表示引用外部环境,并将它与函数捆绑在一起而产生的复合体。

    所谓的自由变量是指局部变量以外的变量,同时自由变量的绑定可预知,所谓的绑定(binding)是指变量名称与其所代表的对象之间的联系。一些早期的计算机语言没有所谓封闭的函数,自由变量在运行时再进行绑定。对于那些拥有开放和封闭函数概念的计算机语言,人们需要一种新的术语来区分这两种函数,于是便有了术语闭包。

    一般而言,第二种观点相对更为准确。因为函数是一些可执行的代码,这些代码在定义函数时被固化,在运行时不会发生任何变化,所以一个函数只有一个实例。而闭包会随着引用环境变化而产生不同的实例。

    在 Python 以及大多数现代计算机语言中,所有函数都是封闭的,也就是说没有自由变量。于是对闭包的定义也从早期”对包含可预知绑定对象的自由变量的函数“变成了”可引用非激活环境的对象的函数“。对 Python 而言,自由变量被绑定到在外围作用域定义的变量。

    Closure in Python

    闭包(closure)是一种引用了外部变量的函数对象,无论该变量所处的作用域是否还存在于内存中。

    举例来说,函数 generate_power_func 返回了另一个函数:

    def generate_power_func(n):
        print "id(n): %X" % id(n)
        def nth_power(x):
            return x**n
        print "id(nth_power): %X" % id(nth_power)
        return nth_power
    

    函数 nth_power 就是一个闭包,它可以访问定义在 generate_power_func 函数中的变量 n,显而易见如果缺少变量 n,函数 nth_power 将是一个不能执行的没有闭合的函数,这个不完整的函数 nth_power 需要变量 n 来让它变成一个完整的函数对象,这种函数就是闭包,换句话说是变量 n 封闭了函数 nth_power

    现在我们调用一下函数 generate_power_func,并将调用结果返回给一个变量 raised_to_4

    >>> raised_to_4 = generate_power_func(4)
    id(n): 28F8A4
    id(nth_power): B6CB4570
    >>> repr(rasied_to_4)
    '<function nth_power at 0xb6cb4570>'
    

    结果是调用函数 generate_power_func(4) 将生成一个 nth_power 函数对象。现在我们将函数 generate_power_func 函数从全局命名空间删除。

    >>> del generate_power_func
    

    然后调用闭包函数 raised_to_4

    >>> rasied_to_4(2)
    16
    

    奇迹出现了,销毁函数 generate_power_func 并没有影响到函数 raised_to_4。我们在函数 generate_power_func 中定义变量 n,并且我们已经销毁了函数 generate_power_func,为什么 raised_to_4 会知道变量 n=4

    这是因为函数对象 nth_power 是由 generate_power_func 产生的一个闭包,闭包会保留来自外围作用域变量的信息。

    __closure__ 属性和 cell 对象

    Python 中函数对象都拥有一个 __closure__ 属性。

    __closure__ 对象返回一个由 cell 对象组成的元组,cell 对象记录了定义在外围作用域的变量信息。

    >>> raised_to_4.__closure__
    (<cell at 0xb6cb7f70: int object at 0x28f8a4>,)
    >>> type(raised_to_4.__closure__[0])
    <type 'cell'>
    >>> raised_to_4.__closure__[0].cell_contents
    4
    

    正如所见,__closure__ 属性引用了一个 int 对象,这个 int 对象就是变量 n。对于那些不是闭包的函数对象来说,__closure__ 属性值为 None。

    Ref:

    Python Closures Explained
    Closures in Python
    闭包的概念、形式与应用

  • 相关阅读:
    Vue之computed与watch的使用
    Vue之组件的生命周期
    Vue之过滤器的使用
    Vue之父子组件的通信
    Vue之组件的使用
    Vue之数据绑定
    Vue之指令系统
    20182316胡泊 课程总结
    20182316胡泊 《数据结构与面向对象程序设计》实验9报告
    20182316胡泊 第10周学习总结
  • 原文地址:https://www.cnblogs.com/ifantastic/p/4376079.html
Copyright © 2020-2023  润新知