没有被字典引用的字符串?

看看这个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。 仅用于字典,它会打印False。 另外,x是一个键还是一个值,或者同上,都没关系。

  • 我认为Python中的每一个对象都是一个引用(与具有原始类型的Java相对,或者说Ruby,它的值是小型int),但现在看来str和int是基本类型,没有引用。 但另一方面,为什么只有在字迹?

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

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

    ---更新---

    Curiouser和curiouser ......它似乎是datetime。{datetime,date,time}类具有相同的“未引用”行为。 现在,我知道AnyStr和Number有一个共同之处:它们的哈希随机化为每会话盐。 但是这没有任何意义,因为即使这些行为仅仅是在字典中的值而不是密钥,也可以观察到行为。 并且值不被散列。 或者他们?


    gcmodule.c

    某些类型的容器不能参与引用循环,因此不需要垃圾收集器进行跟踪。 不追踪这些对象可以降低垃圾收集的成本。 但是,确定哪些对象可能未被跟踪并不是免费的,并且必须权衡成本,并与垃圾收集的好处进行权衡。

    ...

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

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

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

    链接地址: http://www.djcxy.com/p/86247.html

    上一篇: Strings not referenced by dicts?

    下一篇: Rename all columns in a table removing whitespace