Python 无法理解浅拷贝
我知道,为了制作浅拷贝,我们可以使用切片,而且还有一个拷贝模块。但是为什么写入索引“b”会改变id呢 但是为什么写入索引“b”会改变id呢 因为他们现在不同了。如果要检查Python 无法理解浅拷贝,python,deep-copy,shallow-copy,Python,Deep Copy,Shallow Copy,我知道,为了制作浅拷贝,我们可以使用切片,而且还有一个拷贝模块。但是为什么写入索引“b”会改变id呢 但是为什么写入索引“b”会改变id呢 因为他们现在不同了。如果要检查a,a[0]仍然是1而不是99,因为b是副本。如果您不希望出现这种行为,则不会复制: >>> a = [1,2,3] >>> b = a[:] >>> id(a[0]) == id(b[0]) True >>> b[0] = 99 >>>
a
,a[0]
仍然是1
而不是99
,因为b
是副本。如果您不希望出现这种行为,则不会复制:
>>> a = [1,2,3]
>>> b = a[:]
>>> id(a[0]) == id(b[0])
True
>>> b[0] = 99
>>> id(a[0]) == id(b[0])
False
相反,您有以下内容:
>>> a = [1,2,3]
>>> b = a
>>> b[0] = 99
>>> a[0]
99
因为您标记了deepcopy
…只有当列表本身包含可变参数时才有意义。比如说,你有:
>>> a = [1,2,3]
>>> b = a[:]
>>> b[0] = 99
>>> a[0]
1
因此a
是b
,c
是浅拷贝,d
是深拷贝
>>> from copy import deepcopy
>>> a = [[1,2],[3,4]]
>>> b = a
>>> c = a[:]
>>> d = deepcopy(a)
b
与a
相同,但副本不受影响
>>> b[0] = 3
>>> a
[3, [3,4]]
>>> c
[[1,2], [3,4]]
>>> d
[[1,2], [3,4]]
如果替换c
的条目,a
不受影响。但是,如果条目中仍有原始列表,则修改其中一个条目仍会显示在另一个条目中。嵌套列表仍然相同
>>> c[1][1] = 'hi'
>>> a
[3, [3, 'hi']]
>>> c
[[1, 2], [3, 'hi']]
由于d
是一个深度副本,它复制了列表及其嵌套列表,因此我们可以随意修改它及其元素,而不用担心弄乱其他副本
但是为什么写入索引“b”会改变id呢
因为他们现在不同了。如果要检查a
,a[0]
仍然是1
而不是99
,因为b
是副本。如果您不希望出现这种行为,则不会复制:
>>> a = [1,2,3]
>>> b = a[:]
>>> id(a[0]) == id(b[0])
True
>>> b[0] = 99
>>> id(a[0]) == id(b[0])
False
相反,您有以下内容:
>>> a = [1,2,3]
>>> b = a
>>> b[0] = 99
>>> a[0]
99
因为您标记了deepcopy
…只有当列表本身包含可变参数时才有意义。比如说,你有:
>>> a = [1,2,3]
>>> b = a[:]
>>> b[0] = 99
>>> a[0]
1
因此a
是b
,c
是浅拷贝,d
是深拷贝
>>> from copy import deepcopy
>>> a = [[1,2],[3,4]]
>>> b = a
>>> c = a[:]
>>> d = deepcopy(a)
b
与a
相同,但副本不受影响
>>> b[0] = 3
>>> a
[3, [3,4]]
>>> c
[[1,2], [3,4]]
>>> d
[[1,2], [3,4]]
如果替换c
的条目,a
不受影响。但是,如果条目中仍有原始列表,则修改其中一个条目仍会显示在另一个条目中。嵌套列表仍然相同
>>> c[1][1] = 'hi'
>>> a
[3, [3, 'hi']]
>>> c
[[1, 2], [3, 'hi']]
由于
d
是一个深度副本,它复制了列表及其嵌套列表,因此我们可以随意修改它及其元素,而不用担心弄乱其他副本。当您将a
的浅层副本复制到b
(b=a[:]
)时,您复制了它b
在某个特定时间点成为a的副本,这是a的“快照”
当您更新b[0]=99
时,您更新了b
——即a
的副本。您没有更新a
。这就是制作浅(或深)副本的意义所在——您需要一个具有相同内容的新变量,这样您就可以在不影响原始副本的情况下对副本进行更改
如果您希望
b[0]=99
也影响a
,那么您不想“复制”a
,您只想用另一个名称引用它。当您将a
的浅拷贝复制到b
(b=a[:]
)时,您会使用b=ab
在某个特定时间点成为a的副本,这是a的“快照”
当您更新b[0]=99
时,您更新了b
——即a
的副本。您没有更新a
。这就是制作浅(或深)副本的意义所在——您需要一个具有相同内容的新变量,这样您就可以在不影响原始副本的情况下对副本进行更改
如果您希望b[0]=99
也影响a
,那么您不想“复制”a
,您只想用另一个名称引用它。您将使用b=a
第1部分:调用b[0]=99
为什么会导致a[0]==b[0]>>False
?
您的问题的答案是,当您执行b[0]=99
时,您不会“修改b的一个字段指向的内存地址”,而是实际更改b的一个字段指向的位置
>>> d[1][1] = 10
>>> a
[3, [3, 'hi']]
>>> d
[[1, 2], [3, 10]]
现在a
包含对列表
对象的引用,而该列表又包含对三个int
对象的三个引用
a = [1,2,3]
id(a) == id(b)
#False
id(a) == id(b)
# False
现在,b引用一个列表
对象(与a
引用的对象不同),并包含三个对三个int
对象的引用,与a
引用的对象相同
b = a[:]
错误,因为a
和b
是对不同列表
对象的引用
a = [1,2,3]
id(a) == id(b)
#False
id(a) == id(b)
# False
是,因为a[0]
是对1
对象的引用,b[0]
也是如此。只有一个1
对象,它由a[0]
和b[0]
id(a[0]) == id(b[0])
#True
b[0][0] = 99
b
仍然指的是相同的列表
对象,但b[0]
现在指的是99
对象。您只需将b
引用的列表中的一个引用替换为对不同对象的新引用。您没有修改a
指向的任何对象
b[0] = 99
# ^^^^^^ THIS IS NOT WHAT THE WIKIPEDIA ARTICLE IS DESCRIBING
错误,因为1
对象与99
对象不是同一个对象
a = [[1],[2],[3]]
第二部分:那维基百科的文章到底在说什么呢?
下面是一个复制操作的示例,您实际上正在“修改B的一个字段指向的内存地址”,以便可以看到复制对象中的后续更改
id(a[0]) == id(b[0])
#False
a
是对list
对象的引用,但是现在list
对象包含对list
对象的三个引用,每个引用都包含对int
对象的引用
a = [[1],[2],[3]]
与前面一样,您已使b
引用一个新的、不同的列表
对象,该对象引用