为啥相同值的内存地址不同[重复]

Posted

技术标签:

【中文标题】为啥相同值的内存地址不同[重复]【英文标题】:why memory address are not same for same values [duplicate]为什么相同值的内存地址不同[重复] 【发布时间】:2016-12-18 23:52:43 【问题描述】:

考虑下面的代码

a,b="hello","hello" 
print id(a),id(b)

输出

28954752 28954752

char、string 等的输出将相同 但是现在考虑一个列表

list1=[1,2,3,4]
list2=[1,2,3,4]
print id(list1),id(list2)

输出

139706054367136 139706054368360

我们可以看到在列表/元组/字典的情况下给出的地址是不同的,如果它们是引用变量,那么为什么字符串为相同的值给出相同的地址?

【问题讨论】:

哪种行为让您感到惊讶?整数具有相同 ID 的事实,还是列表不具有相同 ID 的事实? 该问题仅针对我询问列表/元组的字符串。 @julienbernu 我对这个答案不满意。 如果您打算任何基于对象 ID 或数据的内存地址的事情,您可能不应该这样做。不同的 Python 解释器(CPython vs. PyPy vs. ActivePython vs. ...)会以不同的方式处理这样的内部细节......我怀疑即使是相同的 Python“品牌”在不同的架构上也会表现不同。 @KevinJ.Chase:理论上,参考解释器能够根据编译选项禁用多个缓存,因此即使在相同的架构上,自定义构建的行为也可能不同。 【参考方案1】:

有时(在设计上它是一个实现细节)Python caches certain values 用于重用。

特别是它只能安全​​地缓存字符串和整数等不可变类型。由于list1list2 是可变的,因此它们在内部引用同一个对象是有问题的,因为其中一个对象的突变会反映在另一个对象中。

假设 Python 有某种列表缓存,这样 list1list2 最终会引用同一个对象:

> print(id(list1) == id(list2))
True
> list1[0] = 5
> print(list2)
[5, 2, 3, 4]

这是一件好事,但它不是这样工作的 - 使用它会很麻烦!

【讨论】:

你的第一行会给出 False @piyushsingh:是的,这就是重点。代码是编造的(注意提示不是真正的 Python 提示)。您必须结合代码阅读周围的文字。 @piyushsingh 对; 如果是真的,就会有问题。因此列表和字符串处理方式的区别。【参考方案2】:
list1=[1,2,3,4]
list2=[1,2,3,4]

创建 2 个碰巧持有相同值的对象。对象不同,它们具有不同的 ID。 (在这种情况下,您可以单独修改其中任何一个。)

list1=list2=[1,2,3,4]

为同一个对象创建 2 个引用。相同的对象具有相同的 ID。 (在这种情况下,您无法在不更改 list2 的情况下修改 list1。)

对于字符串,它有点微妙:python 只创建一个对象"hello",即使你这样做了

a = "hello"
b = "hello"

顺便说一句,您也可以直接致电id("hello") 并找到相同的结果。

【讨论】:

@piyushsingh 编译器正在实习字符串。由于它们是相同的值并且从未更改过,因此创建一个对象并使对该字符串值的所有引用都指向该单个对象是安全的。 您的编辑使您的答案变得更糟。尝试检查更大的 int 值。 @piyushsingh 复杂性。如果可以绝对确定它们从未被修改,它只能实习值。弄清楚这一点可能涉及大量计算,并且 Python 会解释这一点,以便在程序运行时命中。通常,解释器编写者通过将实习限制为仅某些数据类型和声明形式来避免巨大的计算损失(例如,声明一个初始化为文字常量的字符串可能有资格实习,而由另一个字符串变量初始化的可能不适合实习)。 不仅仅是long,还有普通的int。管理 Python 实习行为的规则非常复杂,不容易预测。你可以确定的是,两个可变对象永远不会有相同的地址。两个不可变对象可能有也可能没有相同的地址。关于这些,几乎没有硬性规定。 None 是一个特例,保证是单例的。在我的脑海中,我想不出任何其他人。 @piyushsingh:字符串文字和小整数具有特殊的缓存(空的tuple 也是如此),这意味着共享单个实例。其他对象不这样做,要么是由于可变性,要么是复杂性不值得这些好处。有时他们确实维护了一个空闲列表(tuple 这样做,所以当一个小的 tuple 被释放并且随后分配另一个相同大小的 tuple 时,它实际上并没有执行分配),但它主要是实现细节,并且您通常不应该依赖身份测试来测试任何没有记录的单例(例如None)。

以上是关于为啥相同值的内存地址不同[重复]的主要内容,如果未能解决你的问题,请参考以下文章

shmat()为不同的程序返回不同的地址,所有程序都具有相同的共享内存[重复]

始终强制将内存分配到相同的虚拟地址[重复]

python对于相同值的内存管理

为啥 xxd 和 objdump 的内存地址或偏移量不同?

内存地址和Java HashCode [duplicate]有什么区别

不同的静态全局变量共享相同的内存地址