def test(x):
def add(y):
return x+y
def mul(y):
return x*y
return "test"
var x
会转到GC吗?
答案 0 :(得分:1)
Python使用引用计数来管理对象,而不是变量。如果您想知道何时从内存中清除x
引用的对象,您需要跟踪它有多少引用。 x
只是一个这样的参考。
但是,如果没有其他引用到同一个对象(x
是唯一的引用),那么是的,该对象将从内存中删除,因为两个{ {1}}和add
不会被mul
返回。
test
被这两个嵌套函数用作闭包,因此x
引用的对象将获得两个额外的引用(通过函数对象闭包)。但是由于函数对象在函数结束时被删除(因为它们只是x
中的本地符号),所以它们的闭包也是如此,因此最终的结果是不再有{{1引用的对象的引用在test
通话结束时,就像电话会议开始时一样。
闭包单元在某种程度上并不重要,因为它们跟踪变量,而不是直接跟踪对象。闭包只是Python的对象(尽管在解释器中有特殊支持来帮助跟踪原始引用),因此它们也需要引用计数。
您可以使用sys.getrefcount()
function查看对象的引用数量:
x
引用计数没有改变,因此test()
在函数完成后从未导致其他引用。如果您实际返回了嵌套函数,则会发生这种情况:
>>> import sys
>>> def test(x):
... def add(y):
... return x+y
... def mul(y):
... return x*y
... return "test"
...
>>> value = 'foo bar'
>>> sys.getrefcount(value)
2
>>> test(value)
'test'
>>> sys.getrefcount(value)
2
这两个函数都引用相同的闭包单元格,而后者又引用test
的值,因此当这两个函数对象仍然存在时,引用计数加1。删除这两个函数会清除闭包单元格(该对象的引用数量下降到0),引用计数再次下降。
一旦>>> def test2(x):
... def add(y):
... return x+y
... def mul(y):
... return x*y
... return {'+': add, '*': add}
...
>>> test_result = test2(value)
>>> test_result
{'+': <function add at 0x104e85b90>, '*': <function add at 0x104e85b90>}
>>> sys.getrefcount(value)
3
>>> del test_result['+']
>>> sys.getrefcount(value)
3
>>> del test_result['*']
>>> sys.getrefcount(value)
2
字符串的引用计数变为0,它也将被删除。在上面的示例中,它始终为2,因为每当我尝试访问引用计数时,名称x
和'foo bar'
函数都会引用它。