字符串没有被dicts引用?

时间:2015-06-30 06:58:20

标签: python string dictionary reference cpython

看看这个Python代码:

from gc import get_referrers as refs
x = 'x'
d = {x:x}
print(d in refs(x))

它打印False。这本身就很奇怪,但是当你考虑以下因素时会变得更加怪异:

  • 如果x是一个数字(int,float,complex,Fraction,Decimal)而不是字符串,它仍会输出False。对于字节和bytearray也是如此。但是对于其他所有类型(如果用作键,可以使用,如tuple或frozenset,还有许多其他类型,如果仅用作值),则会打印True。

  • 如果d是包含x的任何其他容器(set,list,tuple ...),则打印为True。只有dict,它打印False。此外,如果x是键或值,或者如上所述,两者都无关紧要。

我认为在Python中每个对象都是一个引用(而不是Java,它有原始类型,或者Ruby,它是值类型小的int),但是现在看起来str和int是有点原始类型,不是引用。但另一方面,为什么只能在dicts?

我也知道在CPython中缓存了从-5到256的整数(并且可以实现小字符串),因此不重新计算它们是有意义的,因为它们永远不会被删除,但这适用于任何整数(我试过了,比那个范围大得多。

有人知道这里发生了什么吗?

---更新---

Curiouser和curiouser ......似乎是datetime。{datetime,date,time}类具有相同的“未引用”行为。现在,我知道一个那些,AnyStr和Number的共同点:它们的哈希值是随机会话盐。但是这并没有使任何意义,因为即使这些行为仅仅是而不是键,也会观察到行为。价值观并没有散播。或者是他们?

1 个答案:

答案 0 :(得分:4)

来自gcmodule.c

  

某些类型的容器无法参与参考周期,并且   所以不需要被垃圾收集器跟踪。解开这些   对象降低了垃圾收集的成本。但是,确定   哪些对象可能未被跟踪不是免费的,成本必须是   权衡了垃圾收集的好处。

     

...

     

仅包含不可变对象的词典也不需要   跟踪。字典在创建时未跟踪。如果是被跟踪的项目   插入字典(作为键或值),字典   跟踪。在完整的垃圾收集(所有代)中,   收藏家将不会删除任何内容不是的词典   跟踪。

基本上,由于Python中的对象是引用计数,因此垃圾收集器的目标是打破引用周期,当最后一个引用消失时,其他未引用的对象将被销毁。为了优化,垃圾收集器不会跟踪某些根本无法参与参考周期的对象。

因此,字符串引用。但是,垃圾收集器根本不对这些字典感兴趣,因此gc.get_referrers()不会列出它们。