dict没有引用元素? Python2.7改变了行为

时间:2013-05-31 12:31:50

标签: python python-2.7 reference garbage-collection python-2.x

举个例子:

>>> import gc
>>> d = { 1 : object() }
>>> gc.get_referrers(d[1])
[] # Python 2.7
[{1: <object object at 0x003A0468>}] # Python 2.5

为什么 d未被列为对象的引用者?

EDIT1:虽然d中的dict引用了该对象,为什么没有列出dictionairy?

2 个答案:

答案 0 :(得分:5)

doc提及:

  

此功能仅定位那些支持垃圾的容器   采集;扩展类型,它引用其他对象但不引用   支持垃圾收集将无法找到。

似乎字典不支持它。

这就是为什么:

  

垃圾收集器试图避免跟踪简单的容器   不能成为一个循环的一部分。在Python 2.7中,现在对于元组来说是正确的   和dicts包含原子类型(如整数,字符串等)。   传递上,包含原子类型元组的dict不会   追踪。这有助于降低每次垃圾回收的成本   通过减少要考虑和遍历的对象数量   收藏家。

     

- 来自What's new in Python 2.7

似乎object()被认为是原子类型,并且尝试使用用户定义类的实例(即不是object)将此确认为你的代码现在有效。

# Python 2.7
>>> class A(object): pass
>>> r = A()
>>> d = {1: r}
>>> del r
>>> gc.get_referrers(d[1])
[{1: <__main__.A instance at 0x0000000002663708>}]

另见issue 4688

答案 1 :(得分:1)

这是对Python 2.7中对象跟踪方式的改变;仅包含原子类型(包括object()的实例)的元组和字典(不再需要循环中断)不再列出。

http://bugs.python.org/issue4688;这是为了避免在创建元组或字典的负载时出现性能问题。

解决方法是在 需要跟踪的词典中添加一个对象:

>>> gc.is_tracked(d)
False
>>> class Foo(object): pass
...
>>> d['_'] = Foo()
>>> gc.is_tracked(d)
True
>>> d in gc.get_referrers(r)
True

一旦跟踪,字典只会在gc收集周期后回到未跟踪状态:

>>> del d['_']
>>> gc.is_tracked(d)
True
>>> d in gc.get_referrers(r)
True
>>> gc.collect()
0
>>> gc.is_tracked(d)
False
>>> d in gc.get_referrers(r)
False