python - Python将函数闭包的名称绑定(bind)存放在哪里?

标签 python closures python-2.x cpython

所以最近才明白函数闭包的概念。

def outer():
    somevar = []
    assert "somevar" in locals() and not "somevar" in globals()
    def inner():
        assert "somevar" in locals() and not "somevar" in globals()
        somevar.append(5)
        return somevar
    return inner

function = outer()
somevar_returned = function()
assert id(somevar_returned) == id(function.func_closure[0].cell_contents)

据我了解,函数闭包的目的是保持对该对象的事件引用,以避免对该对象进行垃圾回收。这就是以下工作正常的原因:

del outer
somevar_returned_2 = function()
assert id(somevar_returned) == id(function.func_closure[0].cell_contents)
assert id(somevar_returned) == id(somevar_returned_2)

在执行 inner 函数之前(据我所知总是如此),Python 会重建局部变量字典。这本词典将包含:

  • 与其单元格内容关联的函数的闭包名称
  • 函数的参数名称与它们的默认值或给定的参数相关联(并且它可以覆盖先前的名称)

问题是 Python 在哪里存储闭包的名称绑定(bind)?我到处都找不到。

注意:函数的属性:

>>> print "\n".join("%-16s : %s" % (e, getattr(function, e)) for e in dir(function) if not e.startswith("_") and e != "func_globals")
func_closure     : (<cell at 0x2b919f6bc050: list object at [...]>,)
func_code        : <code object inner at [...], file "<stdin>", line 4>
func_defaults    : None
func_dict        : {}
func_doc         : None
func_name        : inner

最佳答案

这取决于 python 实现。我假设您指的是 CPython。

__code__(或func_code)有一个co_freevars属性,其中包含所有非局部变量的名称(它们被称为“free vars”,就好像 python 函数是一个逻辑公式,其中参数和局部变量是量化变量)

从这些不同的属性中,您可以获得从本地和非本地名称到单元格的映射。

In [35]: function.__code__.co_freevars
Out[35]: ('somevar',)

co_varnames 属性列出了所有本地定义的名称:

In [36]: function.__code__.co_varnames
Out[36]: ()
In [37]: def outer():
    ...:     somevar = ["stackoverflow"]
    ...:     def inner():
    ...:         x = 1
    ...:         somevar.append(5)
    ...:         return somevar
    ...:     return inner
    ...: 
    ...: function = outer()

In [38]: function.__code__.co_varnames
Out[38]: ('x',)

虽然 co_cellvars 说明哪些本地名称被内部 函数使用:

In [43]: outer.__code__.co_cellvars
Out[43]: ('somevar',)

所有的闭包函数都有 __closure__ 属性。此属性返回单元格对象的元组。并且单元格对象具有存储变量值的cell_contents属性。

In [44]: function.__closure__
Out[44]: (<cell at 0x7f4e06b002b8: list object at 0x7f4e06b522c8>,)
In [45]: function.__closure__[0].cell_contents
Out[45]: ["stackoverflow"]

关于python - Python将函数闭包的名称绑定(bind)存放在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32221063/

相关文章:

Python奇怪的按位与(&)输出

python - get-pip.py 返回 SyntaxError : invalid syntax

python - Spyder 随机无法定位 chromedriver

python - 为什么我无法在 Python 中正确地将项目添加到列表中?

python - 取消对 Gtk.TreeView 中某些特定项目的拖放

python - 为什么这个字符串比较返回 False?

arrays - Swift:使用闭包

javascript - JS 不断更新网格中的 CSS 背景颜色 - 关闭?

javascript - setInterval 中的关闭计数器

python - 实验室 : calculate discounts