Vek*_*eky 7 python string dictionary cpython reference
看看这个Python代码:
from gc import get_referrers as refs
x = 'x'
d = {x:x}
print(d in refs(x))
Run Code Online (Sandbox Code Playgroud)
它打印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是有点原始的类型,没有被引用.但另一方面,为什么只有在说?
我也知道在CPython中缓存了从-5到256的整数(并且可以实现小字符串),因此不重新计算它们是有意义的,因为它们永远不会被删除,但这适用于任何整数(和长字符串)我试过,比那个范围大得多.
有谁知道这里发生了什么?
---更新---
Curiouser和curiouser ......似乎是datetime.{datetime,date,time}类具有相同的"未引用"行为.现在,我知道有一件事,AnyStr和Number有一个共同点:他们的哈希值是随机的,每个会话的盐.但这没有任何意义,因为即使这些行为仅仅是词汇中的值而不是键,也会观察到行为.价值观并没有散播.或者是他们?
小智 4
从gcmodule.c
:
某些类型的容器无法参与引用循环,因此不需要由垃圾收集器跟踪。取消对这些对象的跟踪可以降低垃圾收集的成本。然而,确定哪些对象可能不被跟踪并不是免费的,必须权衡成本与垃圾收集的好处。
...
仅包含不可变对象的字典也不需要被跟踪。字典在创建时未被跟踪。如果将跟踪的项目插入到字典中(作为键或值),则字典将被跟踪。在完整垃圾收集(所有代)期间,收集器将取消跟踪其内容未被跟踪的任何字典。
基本上,由于Python中的对象是引用计数的,垃圾收集器的目标是打破引用循环,当最后一个引用消失时,其他未引用的对象将被销毁。为了优化,垃圾收集器不会跟踪某些永远无法参与引用循环的对象。
因此,字符串被引用。但是,垃圾收集器对这些字典根本不感兴趣,因此gc.get_referrers()
不会列出它们。