>>> a = [1,2,3]
>>> b = a[:]
>>> id(a[0]) == id(b[0])
True
>>> b[0] = 99
>>> id(a[0]) == id(b[0])
False
据我所知,要制作浅色副本,我们可以使用切片,还有一个复制模块。但是为什么写入“b”索引会改变id。
答案 0 :(得分:5)
b[0] = 99
导致a[0] == b[0] >> False
? 你的问题的答案是,当你执行b[0] = 99
时,你没有“修改B字段中的一个指向的内存地址”,你实际上改变了其中一个B是田野点。
a = [1,2,3]
现在a
包含对list
对象的引用,该对象又包含对三个int
对象的三个引用。
b = a[:]
现在b引用list
对象(与a
引用的对象不同),并包含对三个int
对象的三个引用,{{1} }指的。
a
错误,因为id(a) == id(b)
#False
和a
是对不同b
个对象的引用。
list
是的,因为id(a[0]) == id(b[0])
#True
是a[0]
对象的引用,1
也是如此。只有一个b[0]
对象,1
和a[0]
b[0]
b[0] = 99
# ^^^^^^ THIS IS NOT WHAT THE WIKIPEDIA ARTICLE IS DESCRIBING
仍然引用相同的旧b
对象,但list
现在引用b[0]
对象。您只需将99
引用的list
中的一个引用替换为对不同对象的新引用。您已经不修改了b
指向的任何对象!
a
错误,因为id(a[0]) == id(b[0])
#False
对象与1
对象不是同一个对象。
这是一个复制操作的示例,其中您实际上是“修改B字段之一指向的内存地址”,因此您可以看到复制对象中的后续更改。
99
a = [[1],[2],[3]]
是对a
对象的引用,但现在list
对象包含对list
个对象的三个引用,每个对象都包含对{{1}的引用对象。
list
和以前一样,您已经int
引用了一个新的,不同的b = a[:]
对象,该对象引用了b
中引用的三个list
个对象。 。这是证据:
list
错误,因为之前a
和id(a) == id(b)
# False
是对不同a
个对象的引用。
b
是的,因为和以前一样,list
和id(a[0]) == id(b[0])
#True
都指的是同一个对象。这次它是一个a[0]
对象,它不是不可变的,与b[0]
对象不同 - 我们实际上可以更改list
对象的内容! 以下是不同之处:
int
我们做到了 - 我们更改了list
b[0][0] = 99
对象的内容
list
请参阅? b[0]
引用的a[0][0]
# 99 !!!!!!!!!!!!!! Wikipedia doesn't need to be edited!
引用的“列表”现在引用list
对象,而不是a
对象,因为它是相同的{{1}您使用99
访问的内容。简单,呵呵;)
1
是的,因为虽然我们更改了引用list
的内容,但我们 更改了b[0][0] = 99
和id(a[0]) == id(b[0])
#True !!!
中的引用本身 - 这是更接近的维基百科文章在“浅拷贝”部分中描述的内容。
答案 1 :(得分:1)
但为什么写入“b”索引会改变id。
因为他们现在是不同的事情。如果您要检查a
,a[0]
仍然是1
而不是99
,因为b
是副本。如果您不想要这种行为,则不会进行复制:
>>> a = [1,2,3]
>>> b = a
>>> b[0] = 99
>>> a[0]
99
相反,你有这个:
>>> a = [1,2,3]
>>> b = a[:]
>>> b[0] = 99
>>> a[0]
1
由于您标记了deepcopy
...只有在您的列表本身包含可变参数时才会有用。比方说,你有:
>>> from copy import deepcopy
>>> a = [[1,2],[3,4]]
>>> b = a
>>> c = a[:]
>>> d = deepcopy(a)
所以a
是b
,c
是浅版,d
是深层副本。
>>> b[0] = 3
>>> a
[3, [3,4]]
>>> c
[[1,2], [3,4]]
>>> d
[[1,2], [3,4]]
b
与a
相同,但副本不受影响。
>>> c[1][1] = 'hi'
>>> a
[3, [3, 'hi']]
>>> c
[[1, 2], [3, 'hi']]
如果您替换c
的条目,则a
不受影响。但是如果你仍然在条目中有原始列表,那么修改一个列表仍会显示在另一个列表中。嵌套列表仍然相同。
>>> d[1][1] = 10
>>> a
[3, [3, 'hi']]
>>> d
[[1, 2], [3, 10]]
由于d
是一个深层副本,它复制了列表及其嵌套列表,因此我们可以随意修改及其元素,而无需担心其他副本的混乱
答案 2 :(得分:1)
当您将a
的浅层副本复制到b
(b = a[:]
)时,您将其复制了。 b
在特定时间点成为a
的副本 - 它是a的“快照”。
更新b[0] = 99
后,您更新了b
- a
的副本。你没有更新a
。这是制作浅(或深)副本的重点 - 您想要一个具有相同内容的新变量,这样您就可以对副本进行更改而不会影响原始副本。
如果您希望b[0] = 99
也影响a
,那么您不想“复制”a
,您只想通过其他名称引用它。你使用b = a
。
答案 3 :(得分:1)
Python中的列表包含对其内容的引用。
使用a[:]
或copy
方法复制列表时,可以使用相同的引用创建新列表。更改原始列表中的项目时会发生什么情况取决于其类型。
可变对象(如列表)可以就地更改(这就是使它们可变的原因)。两个列表仍然引用相同的对象:
a = [[0],[1],[2]]
b = a[:]
a[0].append[1]
b[0] # >>> [0,1]
另一方面,整数是不可变的。更改整数会创建一个新对象,并带有新的id和引用。
a = [0, 1, 2]
b = a[:]
a[0] = 10
b[0] # >>> 0