44

Beazley pg 100 提到:

>>>python.__closure__
(<cell at 0x67f50: str object at 0x69230>,)
>>>python.__closure__[0].cell_contents

我的理解是这__closure__是一个列表,但是这些单元格的东西和 str 对象是什么?这看起来像一个一元元组?

4

4 回答 4

68

闭包单元指的是函数所需的值,但取自周围的范围。

当 Python 编译嵌套函数时,它会记下它引用但仅在嵌套函数和父范围的代码对象中的父函数(不是全局变量)中定义的任何变量。这些分别是这些函数对象的co_freevarsco_cellvars属性。__code__

然后,当您实际创建嵌套函数(执行父函数时发生)时,这些引用将用于将闭包附加到嵌套函数。

函数闭包包含一个单元元组,每个单元对应一个自由变量(在 中命名co_freevars);单元格是对父作用域的局部变量的特殊引用,它遵循那些局部变量指向的值。最好用一个例子来说明这一点:

def foo():
    def bar():
        print(spam)

    spam = 'ham'
    bar()
    spam = 'eggs'
    bar()
    return bar

b = foo()
b()

在上面的例子中,函数bar有一个闭包单元,它指向spam函数中的foo。单元格遵循 的值spam。更重要的是,一旦foo()完成并返回,即使里面的变量不再存在bar,单元格也会继续引用该值(字符串)。eggsspamfoo

因此,上面的代码输出:

>>> b=foo()
ham
eggs
>>> b()
eggs

并且b.__closure__[0].cell_contents'eggs'

请注意,闭包在被调用bar()被取消引用;闭包并没有捕捉到这里的价值。当您生成引用循环变量的嵌套函数(使用lambda表达式或语句)时,这会有所不同:def

def foo():
    bar = []
    for spam in ('ham', 'eggs', 'salad'):
        bar.append(lambda: spam)
    return bar

for bar in foo():
    print bar()

上面将连续打印salad三次,因为所有三个lambda函数都引用了spam变量,而不是创建函数对象时绑定的值。到for循环结束时,spam已绑定到'salad',因此所有三个闭包都将解析为该值。

于 2013-01-19T12:59:54.690 回答
11

它是旧的 Python 3 的新名称func_closure

http://docs.python.org/3.0/whatsnew/3.0.html

已命名的函数属性func_X已重命名为使用__X__表单,从而在函数属性命名空间中为用户定义的属性释放这些名称。也就是说,func_closure, func_code, func_defaults, func_dict, func_doc, func_globals,func_name分别重命名为__closure__, __code__, __defaults__, __dict__, __doc__, __globals__, __name__

简而言之:

__closure__isNone或 atuple包含对函数的自由变量的绑定的单元格。

此外,它不可写。

参考:http ://docs.python.org/ref/types.html

示例Python < 3(所以我正在使用func_closure

def foo():
    x = "I am used"
    y = "I am free"
    z = "I am free too"

    def bar(x):
        return x, y, z

    return bar

c = foo().func_closure

print [i.cell_contents for i in c]

输出:

>>> 
['I am free', 'I am free too']

就像foo返回bar使用自己的值的函数一样x,但不是yor z。所以,他们归于__closure__.

于 2013-01-19T11:51:38.853 回答
2

closure在 python 中定义嵌套函数()时:
外部函数用于co_cellvars记录外部函数中定义的变量,这些变量可以被内部函数引用。
内部函数用于co_freevars记录外部函数中定义的变量,供以后使用。

例子:

# python3
Python 3.4.5 (default, May 29 2017, 15:17:55) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo(n):
...     a = 1
...     def g(n):
...             return a - n
...     return g
... 
>>> foo.__closure__
>>> foo.__code__.co_freevars
()
>>> foo.__code__.co_cellvars
('a',)
>>> foo(0).__closure__
(<cell at 0x7f2cd98db1c8: int object at 0x7f2cd9847960>,)
>>> foo(0).__closure__[0].cell_contents
1
>>> foo(0).__code__.co_freevars
('a',)
>>> foo(0).__code__.co_cellvars
()
于 2018-05-15T13:18:12.213 回答
1
>>> def f():
...     a = "HELO"
...     b = 1.0
...     def w(c):
...         return a,b,c
...     return w

>>> w = f()
>>> w.__closure__
(<cell at 0xa05c4ac: str object at 0x9e91b74>, <cell at 0xa05c3bc: float object at 0xb733dde8>)
>>> w.__closure__[0].cell_contents
'HELO'
>>> w.__closure__[1].cell_contents
1.0

我从未见过其他地方使用过的细胞类型。它似乎是专门为保存闭包变量而设计的。

于 2013-01-19T11:56:58.627 回答