Python dicts未引用的字符串?
请看以下Python代码:Python dicts未引用的字符串?,python,string,dictionary,reference,cpython,Python,String,Dictionary,Reference,Cpython,请看以下Python代码: from gc import get_referrers as refs x = 'x' d = {x:x} print(d in refs(x)) 它印的是假的。这本身就很奇怪,但是当你考虑以下情况时变得更加奇怪: 如果x是一个数字(int、float、复数、分数、十进制)而不是一个字符串,它仍然打印False。对于字节和字节数组也是如此。但对于其他每一种类型(如果用作键,如tuple或frozenset,则为hashable,但如果仅用作值,则为许多其他类型)
from gc import get_referrers as refs
x = 'x'
d = {x:x}
print(d in refs(x))
它印的是假的。这本身就很奇怪,但是当你考虑以下情况时变得更加奇怪:
- 如果x是一个数字(int、float、复数、分数、十进制)而不是一个字符串,它仍然打印False。对于字节和字节数组也是如此。但对于其他每一种类型(如果用作键,如tuple或frozenset,则为hashable,但如果仅用作值,则为许多其他类型),它都打印为True
- 如果d是包含x的任何其他容器(集合、列表、元组…),它将打印True。只有口述,它打印的是假的。另外,x是键还是值,或者如上所述,两者都是,这并不重要
好奇者和好奇者。。。似乎是datetime。{datetime,date,time}类具有相同的“未引用”行为。现在,我知道AnyStr和Number有一个共同点:它们的散列是随机的,每会话一次。但这没有任何意义,因为即使这些只是dict中的值,而不是键,也会观察到行为。和值不进行散列。还是它们?来自
gcmodule.c
:
某些类型的容器不能参与引用循环,以及
因此不需要由垃圾收集器跟踪。解开这些
对象降低了垃圾收集的成本。然而,决定
哪些对象可能未被跟踪不是免费的,而且成本必须是合理的
权衡垃圾收集的好处
只包含不可变对象的字典也不需要修改
跟踪。词典创建时不受跟踪。如果跟踪的项目是
插入字典(作为键或值),字典
被跟踪。在完整垃圾收集期间(所有代),
收集器将取消跟踪内容不正确的任何词典
跟踪
基本上,由于Python中的对象是引用计数,垃圾收集器的目标是打破引用周期,当最后一个引用消失时,其他未引用的对象将被销毁。为了进行优化,垃圾收集器不跟踪某些对象,因为这些对象永远无法参与引用循环
因此,字符串被引用。但是,垃圾收集器对这些字典根本不感兴趣,因此
gc.get\u referers()
不会列出它们。有趣的是,分配字典后引用计数(sys.getrefcount
)会增加2。但是如果键和值不同(其中一个是x),那么get_referers
甚至返回False,因此它似乎不能防止循环引用。是的,这是我的假设之一,但正如您所说,它不成立,因为x不必同时是键和值。和其他容器(列表)可以有循环引用,它们不会表现出这种行为。顺便说一句,Python 2.7和3.4中的症状类似,引用计数的总数明显不同,这是意料之中的。刚刚发现,在源代码中,你也比我快。有趣的是,如果该值是不可变的(键不能是),那么该值将出现在get\u referers()
中,但该键从未出现过,这可能会与引号相矛盾(尽管它说字典将被跟踪,而不是键)。删除最后一条注释。如果(我猜)缓存了密钥,则不会跟踪它。将x
更改为“Slartibartfast”,将值更改为[1,2,3,4]
,在gc.get\u referers()
中提供键和值作为跟踪。很明显,这里有一些魔力。正如拉里·沃尔(Larry Wall)曾经说过的那样,似乎把源头变大对灵魂真的有好处。:-)谢谢但我还是不明白为什么只有听写而没有录音。。。就好像在Python中集合实际上是二级对象一样。:-)