字典未引用的字符串?

Strings not referenced by dicts?

看看这个 Python 代码:

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

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

我认为在 Python 中每个对象都是一个引用(与具有基本类型的 Java 或 Ruby 相对,后者的值类型为小整数),但是现在似乎 str 和 int 有点原始类型,未被引用。但另一方面,为什么只在字典中??

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

有人知道这是怎么回事吗?

---更新---

越来越好奇...似乎 datetime.{datetime, date, time} 类 具有相同的 "unreferenced" 行为。现在,我知道 one 那些 AnyStr 和 Number 的共同点:它们的散列是随机的,每个会话都有一个盐。但这并没有使 any 有意义,因为即使这些只是 values in dicts 而不是键,也会观察到行为。并且值没有散列。或者他们是?

来自gcmodule.c

Certain types of container cannot participate in a reference cycle, and so do not need to be tracked by the garbage collector. Untracking these objects reduces the cost of garbage collections. However, determining which objects may be untracked is not free, and the costs must be weighed against the benefits for garbage collection.

...

Dictionaries containing only immutable objects also do not need to be tracked. Dictionaries are untracked when created. If a tracked item is inserted into a dictionary (either as a key or value), the dictionary becomes tracked. During a full garbage collection (all generations), the collector will untrack any dictionaries whose contents are not tracked.

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

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