我在Windows上的Python 3.7中玩sys.getrefcount
。我尝试了以下方法:
>>> import sys
>>> x = "this is an arbitrary string"
>>> sys.getrefcount(x)
2
我知道引用之一是x
,另一个是sys.getrefcount
内部使用的参数。无论将x
初始化为哪种类型,这似乎都有效。但是,当我在通过之前未分配时,我注意到了一些奇怪的行为:
>>> import sys
>>> sys.getrefcount("arbitrary string")
2
>>> sys.getrefcount(1122334455)
2
>>> sys.getrefcount(1122334455+1)
2
>>> sys.getrefcount(frozenset())
2
>>> sys.getrefcount(set())
1
>>> sys.getrefcount(object())
1
>>> sys.getrefcount([])
1
>>> sys.getrefcount(lambda x: x)
1
>>> sys.getrefcount(range(1122334455))
1
>>> sys.getrefcount(dict())
1
>>> sys.getrefcount(())
8341
>>> sys.getrefcount(tuple())
8340
>>> sys.getrefcount(list("arbitrary string"))
1
>>> sys.getrefcount(tuple("arbitrary string"))
1
>>> sys.getrefcount(("a", "r", "b", "i", "t", "r", "a", "r", "y", " ", "s", "t", "r", "i", "n", "g"))
2
这是怎么回事?似乎不可变类型有两个引用,但可变类型只有一个?为什么看起来有些对象在传递之前已分配,而另一些对象却只将引用作为参数?
这与str
/ int
/ tuple
实习有关吗?
编辑:一个更直接的问题:为什么选择frozenset()
这样的不可变类型在构造时具有引用,而set()
这样的可变类型却没有?我孤立地了解了为什么您可能会选择保留此全球范围的参考,而不是全部保留,但是为什么会有差异呢?
答案 0 :(得分:1)
一个有趣的问题,所以这里是一个有趣的read。
您应该尝试getrefcount(2)
,对我来说它返回了93,这意味着CPython会为同一内存地址保留93个引用,并保留第二个数字,因此它不必再次分配它,因为它是不可变的这样做完全没问题。
现在让我们尝试两种不同的方法:
# first
getrefcount(set()) # returns 1
# second
s = set()
getrefcount(s) # returns 2
由于它是可变类型,因此当您创建可变类型(set()
)时,其行为会有所不同,它将在内存中分配该类型,并且只有一个对其的引用,该引用将在此行末尾删除。但是在第二个步骤中,我们定义了变量并对其进行了分配,在计算引用数时,我们有一个s
使用的变量和一个在函数getrefcount
内部使用的变量。
在Python tuples are immutable中,这就是它返回大量数字的原因,CPython保留了大量对空元组的引用。