python: 可变对象的 id() - 解释有趣的模式?

python: id() of mutable object - explanation interesting pattern?

以下模式在调用具有相等值的可变对象的标识时出现。 如您所见,由 id(mutObj) 编辑的值 return 并不完全独立于 id(mutObj) 的先前 return 值,但模式不稳定。

此行为对于 Python 代码本身可能无关紧要,但我非常有兴趣了解底层机制!

>>> id([1,2])
6706248
>>> id([1,2])
59597256
>>> id([1,2])
56866632
>>> id([1,2])
56866632
>>> id([1,2])
56881992
>>> id([1,2])
56881992
>>> id([1,2])
56879624
>>> id([1,2])
56867784
>>> id([1,2])
56867784
>>> id([1,2])
56879624

Python 3.4.3 [MSC v.1600 64 位 (AMD64)] on win32

请特别注意,最后一个值等于前面 return 三个调用的值。

立即 re-use 的 id

Python 对您创建的所有对象使用相同的 id

>>> for x in range(10):
        print(id([1, 2]))
4479841736
4479841736
4479841736
4479841736
4479841736
4479841736
4479841736
4479841736
4479841736
4479841736

因为没有对创建列表的引用,它会立即被垃圾回收,id 将是 re-used。

重复使用同一个名字

将列表分配给名称 obj,将使列表保持活动状态,直到将新列表分配给相同的名称:

>>> for x in range(10):
        obj = [1, 2]
        print(id(obj))
4486925128
4486925192
4486925128
4486925192
4486925128
4486925192
4486925128
4486925192
4486925128
4486925192

在第二次迭代中 obj 存在并且 obj = [1, 2] 在分配给 obj 之前先创建新列表。分配后,旧列表将被垃圾收集,id 再次可用于 re-use。在接下来的每次迭代中重复此操作。

保留参考

当您在列表中保留对所有已创建列表的引用时:

>>> objs = []
>>> for x in range(10):
        obj = [1, 2]
        print(id(obj))
        objs.append(obj)
4480011848
4483963144
4486916488
4486914376
4486914568
4486916616
4486914824
4486915016
4486915272
4486915464

Python 必须对所有这些使用不同的 id

口译效果

在标准交互式提示 (Python 3.5.1) 下工作,我可以生成:

>>> id([1, 2])
4330529608
>>> id([1, 2])
4330529608
>>> id([1, 2])
4330529608
>>> id([1, 2])
4330529608
>>> id([1, 2])
4330529608
>>> id([1, 2])
4330529608

但是在 IPython 或 IPython Notebook 中工作,您会得到:

In [1]: id([1, 2])
Out[1]: 4359684552

In [2]: id([1, 2])
Out[2]: 4379935816

In [3]: id([1, 2])
Out[3]: 4373482696

In [4]: id([1, 2])
Out[4]: 4359674248

In [5]: id([1, 2])
Out[5]: 4373482696

这是因为 IPython 在后台做了更多工作并创建了 re-use 释放的对象 id,然后才能创建新对象。

引自the docs(强调我的):

id(object)

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

基本上,当您编写 id([1, 2]) 时,您创建了一个列表,检查它的 id,然后将其丢弃,这使得它符合垃圾收集的条件。在 CPython 中,由于通过引用计数进行垃圾回收,它随后被删除,并且没有什么禁止在内存中完全相同的位置创建另一个对象,因此具有相同的 id.