Python 中id()
函数的接口(interface)我很清楚:
“对象的身份一旦创建就永远不会改变”[1] , 和
“这是一个整数,保证该对象在其生命周期内是唯一且不变的。” [2]
但是这个声明在[1]让我感到困惑:“你可能会认为它是对象在内存中的地址”。
问题是不清楚对象在内存中的地址是什么以及它是如何变化的。我认为这确实是一个实现细节。这question似乎建议 Language Reference 中的此声明成立,对象的虚拟地址绝不能在实现中更改。
我的问题是:
这个地址指的是虚拟内存地址还是物理内存地址?任何进程的物理地址都是在运行时由操作系统确定的,所以我看不出它是如何成为物理地址的。
实现如何保持虚拟对象地址不变,同时避免内部碎片?相比之下,在 Java 中,JVM 例程在 GC 期间移动对象。
最佳答案
对象的 id
实际上是实现定义的,只要它 a) 在其生命周期内 是唯一且不变的(虽然与此无关)问题:这确实意味着如果第一个对象的生命周期结束,则两个对象可以具有相同的 id
。
CPython 实现确实具有不变性,即对象始终固定在其原始内存位置并且永远不会移动。这在与 C 的互操作性方面有巨大的好处,因为您可以自由地传递指针,只要对象保持事件状态(通常只是一个递增的引用计数器),这些指针就保持有效。
鉴于此,CPython 解释器简单地使用对象的虚拟内存地址作为它的 id
:
- 虚拟地址对于每个对象都是唯一的,因为可以确定它们不是同一对象的任何两个对象必须位于不同的内存位置。
- 使用对象的虚拟地址作为它的
id
总是安全的,因为如果要存储id
,删除原始对象,重新使用id
(我以前见过这个对象吗?)并陷入困惑,他违反了id
仅在以下时间内有效的规则它所代表的对象是活的。
另请注意,重新分配不会更改对象的虚拟地址。例如,list
object有一个指向元素向量的内部指针。 list
对象的 id
是 PyListObject
本身的虚拟地址。当列表增长并需要重新分配/移动到其他地方时,仅更改内部指针; PyListObject
保持原样,因此它的 id
保持不变。
这是 entire definition of the built-in id()
来自当前 HEAD
的函数:
static PyObject *
builtin_id(PyModuleDef *self, PyObject *v)
{
return PyLong_FromVoidPtr(v);
}
没有烟,没有镜子。这只是指针。
关于python - Python文档和实现中“内存中 "object’s地址的细微差别”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50298005/