Fun*_*ayu 7 python closures cpython python-2.x
所以最近我理解了函数闭包的概念.
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)
Run Code Online (Sandbox Code Playgroud)
根据我的理解,函数闭包的目的是保持对对象的活动引用,以避免垃圾收集此对象.这就是为什么以下工作正常:
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)
Run Code Online (Sandbox Code Playgroud)
在执行inner函数之前,事情是(总是和我理解的一样),Python重建了locals变量字典.这本词典将包含:
问题是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
Run Code Online (Sandbox Code Playgroud)
这取决于python实现.我猜你的意思是CPython.
该__code__(或func_code)有一个co_freevars包含所有非本地变量的名称(他们被称为"免费增值经销商",仿佛蟒蛇功能是这里的参数和局部变量进行量化变量的逻辑公式)属性
从这些不同的属性中,您可以获得从本地和非本地名称到单元格的映射.
In [35]: function.__code__.co_freevars
Out[35]: ('somevar',)
Run Code Online (Sandbox Code Playgroud)
该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',)
Run Code Online (Sandbox Code Playgroud)
虽然co_cellvars说内部函数使用了哪些本地名称:
In [43]: outer.__code__.co_cellvars
Out[43]: ('somevar',)
Run Code Online (Sandbox Code Playgroud)
所有闭包函数都有__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"]
Run Code Online (Sandbox Code Playgroud)