>>> 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。
>>> 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。
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对象的三个引用,与引用的对象相同a。
id(a) == id(b)
#False
错误,因为a和b是对不同list对象的引用。
id(a[0]) == id(b[0])
#True
是的,因为a[0]是对对象的引用1,所以也是b[0]。只有一个1对象,它由a[0]and引用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
False,因为1对象与对象不是同一个99对象。
这是一个复制操作的示例,您实际上是在“修改 B 的一个字段指向的内存地址”,因此您可以看到复制对象的后续更改。
a = [[1],[2],[3]]
a是对list对象的引用,但现在该list对象包含三个对list对象的引用,每个引用都包含对一个int对象的引用。
b = a[:]
和以前一样,您已经b引用了一个新的、不同的list对象,它引用了 .samelist中提到的三个对象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
我们做到了——我们改变了引用的对象的内容listb[0]
a[0][0]
# 99 !!!!!!!!!!!!!! Wikipedia doesn't need to be edited!
看?list现在被引用的“列表”a指的是99对象,而不是1对象,因为它与list您使用 访问的相同b[0][0] = 99。很简单,呵呵;)
id(a[0]) == id(b[0])
#True !!!
是的,因为虽然我们更改了a[0]引用的内容,但我们并没有更改引用本身,a[0]并且b[0]- 这更接近 Wikipedia 文章在“浅拷贝”部分中描述的内容。
但是为什么写入“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是深层副本,它复制了列表及其嵌套列表,因此我们可以随意修改它及其元素,而不必担心会弄乱其他副本。
当您制作ato b( b = a[:]) 的浅拷贝时,您复制了它。 在特定时间点b成为副本——它是 a 的“快照”。a
当您更新时b[0] = 99,您更新b了 - 的副本a。你没有更新a。这就是制作浅(或深)副本的重点——您想要一个具有相同内容的新变量,这样您就可以在不影响原始副本的情况下对副本进行更改。
如果你也想b[0] = 99影响a,那么你不想“复制” a,你只想用另一个名字来引用它。你会用b = a.
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