Python函数闭包的名称绑定存放在哪里?
Where does Python store the name binding of function closure?
所以最近才明白函数闭包的概念
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)
据我了解,函数闭包的objective是保持对对象的主动引用,以避免对这个对象进行垃圾回收。这就是以下工作正常的原因:
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 在哪里存储闭包的名称绑定?我到处都找不到。
注意:函数的属性:
>>> 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 中的函数首先是 class 个对象。因此,通过检查函数对象,我们可以对闭包有更多的了解。所有 Python 函数都有一个 closure 属性,让我们检查与闭包函数关联的封闭变量。
>>> def f():
... pass
...
>>> repr(f); repr(f.__closure__)
'<function f at 0x0153A330>'
'None'
这取决于 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 = ["Whosebug"]
...: def inner():
...: x = 1
...: somevar.append(5)
...: return somevar
...: return inner
...:
...: function = outer()
In [38]: function.__code__.co_varnames
Out[38]: ('x',)
虽然 co_cellvars
表示 inner 函数使用了哪些本地名称:
In [43]: outer.__code__.co_cellvars
Out[43]: ('somevar',)
所有闭包函数都有__closure__
属性。此属性 returns 单元格对象的元组。并且单元格对象具有存储变量值的 cell_contents
属性。
In [44]: function.__closure__
Out[44]: (<cell at 0x7f4e06b002b8: list object at 0x7f4e06b522c8>,)
In [45]: function.__closure__[0].cell_contents
Out[45]: ["Whosebug"]
所以最近才明白函数闭包的概念
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)
据我了解,函数闭包的objective是保持对对象的主动引用,以避免对这个对象进行垃圾回收。这就是以下工作正常的原因:
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 在哪里存储闭包的名称绑定?我到处都找不到。
注意:函数的属性:
>>> 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 中的函数首先是 class 个对象。因此,通过检查函数对象,我们可以对闭包有更多的了解。所有 Python 函数都有一个 closure 属性,让我们检查与闭包函数关联的封闭变量。
>>> def f():
... pass
...
>>> repr(f); repr(f.__closure__)
'<function f at 0x0153A330>'
'None'
这取决于 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 = ["Whosebug"]
...: def inner():
...: x = 1
...: somevar.append(5)
...: return somevar
...: return inner
...:
...: function = outer()
In [38]: function.__code__.co_varnames
Out[38]: ('x',)
虽然 co_cellvars
表示 inner 函数使用了哪些本地名称:
In [43]: outer.__code__.co_cellvars
Out[43]: ('somevar',)
所有闭包函数都有__closure__
属性。此属性 returns 单元格对象的元组。并且单元格对象具有存储变量值的 cell_contents
属性。
In [44]: function.__closure__
Out[44]: (<cell at 0x7f4e06b002b8: list object at 0x7f4e06b522c8>,)
In [45]: function.__closure__[0].cell_contents
Out[45]: ["Whosebug"]