闭包详解(Python为例)

不能简单讲,这就要看一些底层的东西(堆栈结构等等,估计还和编译原理有关),我觉得重点在于延迟绑定怎么知道绑定的外层函数的局部变量


python的闭包是延迟绑定

什么是闭包?
  1. 出现函数嵌套, 即外层函数嵌套内层函数, 这就意味着c没有闭包,因为函数不能嵌套定义, 我猜的, 这块打个flag
  2. 内部函数引用外部函数的局部变量 一般我们知道,在栈中的局部变量在函数后退出后就销毁了, 那有什么办法可以不立即这么做?
  3. 外部函数返回值必须是内嵌函数

talk is cheap
#!/usr/bin/python
# -*- coding:utf-8 -*-


def multipliers():
    name = "江湖狗哥我也"
    i = 0
    ret = list()
    for _ in range(4):
        lambda_func = lambda x: i * x + (print(name) is None) - 1 # noqa
        ret.append(lambda_func)
        print(lambda_func.__closure__)
        print("the closure variable i: {}".format(hex(id(lambda_func.__closure__[0].cell_contents))))
        i += 1
    i = 100

    return ret


if __name__ == '__main__':
    for item in multipliers():
        print("the lambda function output: {}".format(item(2)))
        print("闭包中的cell对象组成的元组成: {}".format(item.__closure__))
        print("取出闭包空间中的整数: {}".format(item.__closure__[0].cell_contents))

    for number in list([0, 1, 2, 3, 100]):
        print(hex(id(number)))

__

result

(<cell at 0x0000029926818FD0: int object at 0x0000029926026910>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
the closure variable i: 0x29926026910
(<cell at 0x0000029926818FD0: int object at 0x0000029926026930>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
the closure variable i: 0x29926026930
(<cell at 0x0000029926818FD0: int object at 0x0000029926026950>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
the closure variable i: 0x29926026950
(<cell at 0x0000029926818FD0: int object at 0x0000029926026970>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
the closure variable i: 0x29926026970
江湖狗哥我也
the lambda function output: 200
闭包中的cell对象组成的元组成: (<cell at 0x0000029926818FD0: int object at 0x00000299260555D0>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
闭包中的整数值: 100
江湖狗哥我也
the lambda function output: 200
闭包中的cell对象组成的元组成: (<cell at 0x0000029926818FD0: int object at 0x00000299260555D0>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
闭包中的整数值: 100
江湖狗哥我也
the lambda function output: 200
闭包中的cell对象组成的元组成: (<cell at 0x0000029926818FD0: int object at 0x00000299260555D0>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
闭包中的整数值: 100
江湖狗哥我也
the lambda function output: 200
闭包中的cell对象组成的元组成: (<cell at 0x0000029926818FD0: int object at 0x00000299260555D0>, <cell at 0x0000029926818FA0: str object at 0x0000029926576DC0>)
闭包中的整数值: 100
0x29926026910
0x29926026930
0x29926026950
0x29926026970
0x299260555d0

我特意加了一个字符串局部变量, name, 这里其实声明普通函数也可以,特意用了一些比较恶心的用法.
从下面代码我们知道什么

  1. 闭包空间就是一个元组,元素为cell对象, 每个cell对象又包含闭包内容和其它的内容
  2. 每个lambda函数引用外部函数的局部变量name和i这才形成了闭包
  3. 我在局部函数中把i值最后改成100,可以看到最后所有闭包空间中的int都是100了, 这个很合理,因为我改的是
    局部变量,你引用了啊(这里我感觉既不是值传递也不是引用传递, 更不是共享传参, 就好像我盯着i这个标签一样,你怎么变,我最终值就怎么变)
  4. 可以看到multipliers()调用之后就会出现延迟绑定, 即我所有匿名函数(这里是否是匿名函数没有关系), 最终闭包空间的所有值都是100

—————
延迟绑定只是一个表面现象,真正要理解我觉得还有一段路要走

看完龙书再回答一波.

上一篇:boost::lexical_cast用法的测试程序


下一篇:OS Week1-L1: Intro