哪些类型的Python对象是使用引用初始化的,哪些不是?

时间:2019-06-07 02:53:29

标签: python reference garbage-collection cpython

我在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()这样的可变类型却没有?我孤立地了解了为什么您可能会选择保留此全球范围的参考,而不是全部保留,但是为什么会有差异呢?

1 个答案:

答案 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保留了大量对空元组的引用。