Python 如果列表中的元素指向相同的内存地址,那么这两个列表如何不引用相同的对象?

Python 如果列表中的元素指向相同的内存地址,那么这两个列表如何不引用相同的对象?,python,list,data-structures,Python,List,Data Structures,我初始化两个列表,如下所示: >>> a = [1] >>> b = [1] 然后找到两个列表的索引0处元素的内存位置: >>> id(a[0]) 93961440619840 >>> id(b[0]) 93961440619840 两个元素的地址相同。但是当我试图找出两个列表是否都引用了同一个对象时,我得到了“False” >>> a is b False 我的问题是,如果列表的元素引用相同的内存,

我初始化两个列表,如下所示:

>>> a = [1]
>>> b = [1]
然后找到两个列表的索引0处元素的内存位置:

>>> id(a[0])
93961440619840
>>> id(b[0])
93961440619840
两个元素的地址相同。但是当我试图找出两个列表是否都引用了同一个对象时,我得到了“False”

>>> a is b
False

我的问题是,如果列表的元素引用相同的内存,为什么列表不引用相同的对象?

只有索引0处元素的内存位置相等,而不是整个列表的内存地址

a[0] is b[0] # This returns True
整个列表的内存位置不同:您可以通过键入

id(a)
id(b)

Python这样做是为了减少内存使用

如果您检查
a[0]是b[0]
,那么它将是
True
。因为
a[0]
b[0]
的元素是相同的,这就是为什么这些ID也是相同的。结果是
True

a = [1]
b = [1]
print(a[0] is b[0])
print(id(a[0]), id(a[0]))

# Output
# True
# 1793259440 1793259440
现在为什么
a是b
是False?因为a和b是不同的列表,具有不同的id

print(a is b)
print(id(a), id(b))

# Output
# False
# 9997064 9997800
我的问题是,如果列表的元素引用相同的内存,为什么列表不引用相同的对象

因为列表是可变对象,所以每个列表文字必须创建一个全新的列表对象,独立于以前的每个列表对象^[0]。否则

>a=[]
>>>b=[]
>>>a.1(1)
>>>印刷品(b)
将打印
[1]
而不是空列表,这将是疯狂的

id(a[0])
id(b[0])
虽然是不同的文本,但它们是相同的,这是因为Python可以预先分配/插入经常使用的不可变对象,以降低内存消耗

这是一个不可依赖的实现细节,因为它是特定实现的内部属性,可以随时更改。目前,CPython将预分配-5到256(包括)之间的所有整数,因此即使您通过独立的文字或计算创建它们,这些对象也将始终是相同的对象


[0]从技术上讲,cpython(同样是特定实现的内部细节)维护对象的自由列表,因此当列表被“收集”时,它实际上会被存储起来,以便下次我们需要列表时可以重用分配,而不必重新分配和设置一个全新的列表。这意味着连续(但不是同时)使用的不同列表可以具有相同的
id
,即使同时有许多其他分配。

a
b
是不同的对象,因此
id(a)
不等于
id(b)

但是
a[0]
常量
1
,等于
b[0]
,并且它们的地址相同,以节省内存


帮助这有帮助。

很明显,“a”和“b”是不同的,问题是为什么它们不同?即使它的元素属于同一个内存地址,“a”和“b”是不同的列表对象,也可以向其中添加相同的元素,但它们是两个不同的容器。即使两个空列表对象也是不同的,但您可以说它们都没有元素。在您的示例中,如果“a”和“b”在初始化时是同一个对象,因为它们的元素都没有(或相同),那么在内存方面不是会更有效吗,然后“a”和“b”变成不同的对象。这可能是一种幕后策略,但它是不可见的:在cpython中,
id
实际上是对象在内存中的位置,在适当的位置修改对象不能更改此信息,它不能“回过头来”并更新所有指针对象的指针。因此,实现这一点的方法要求您拥有不同的
id
,不管怎样,这只是因为两者都是同一底层事物的薄立面,然后在需要时更新自己到其他事物。