首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法理解浅拷贝

无法理解浅拷贝
EN

Stack Overflow用户
提问于 2013-08-16 02:38:19
回答 4查看 167关注 0票数 1
代码语言:javascript
复制
>>> 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。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-08-16 03:48:22

b[0] = 99第1部分:为什么调用会导致 a[0] == b[0] >> False**?**

对您的问题的回答是,当您执行b[0] = 99时,您不需要“修改B的一个字段所指向的内存地址”,而是更改B的某个字段所指向的位置。

代码语言:javascript
复制
a = [1,2,3]  

现在,a包含对一个list对象的引用,而该对象又包含对三个int对象的三个引用。

代码语言:javascript
复制
b = a[:]

现在,b引用list对象(与a引用的对象不同),并包含对三个int对象的引用,与a引用的引用相同。

代码语言:javascript
复制
id(a) == id(b)
#False

False,因为ab是对不同list对象的引用。

代码语言:javascript
复制
id(a[0]) == id(b[0])
#True

是,因为a[0]是对1对象的引用,b[0]也是。只有一个1对象,由a[0]b[0]引用。

代码语言:javascript
复制
b[0] = 99  
# ^^^^^^ THIS IS NOT WHAT THE WIKIPEDIA ARTICLE IS DESCRIBING

b仍然引用相同的旧list对象,但是b[0]现在引用99对象。您只需将b引用的b中的一个引用替换为对另一个对象的新引用。您有而不是修改了a指向的任何对象!

代码语言:javascript
复制
id(a[0]) == id(b[0]) 
#False

False,因为1对象与99对象不是同一个对象。

第2部分:维基百科的文章到底在谈论什么?

下面是一个复制操作的示例,您实际上是在“修改B的一个字段所指向的内存地址”,这样您就可以看到复制对象中的后续更改。

代码语言:javascript
复制
a = [[1],[2],[3]]

a是对list对象的引用,但现在list对象包含对list对象的三个引用,每个引用都包含对int对象的引用。

代码语言:javascript
复制
b = a[:]

和前面一样,您已经让b引用了一个新的、不同的list对象,它引用了与a中引用的相同的三个list对象。这是证据:

代码语言:javascript
复制
id(a) == id(b)
# False

False,因为与以前一样,ab是对不同list对象的引用。

代码语言:javascript
复制
id(a[0]) == id(b[0]) 
#True

是的,因为和以前一样,a[0]b[0]都引用同一个对象。这一次它是一个list对象,它不是不可变的,不像int对象--我们实际上可以更改list对象的内容!的地方是不同的:

代码语言:javascript
复制
b[0][0] = 99  

我们做到了-我们更改了由引用的list对象的list内容

代码语言:javascript
复制
a[0][0]
# 99 !!!!!!!!!!!!!!  Wikipedia doesn't need to be edited!

看见?list引用的'list‘现在引用的是99对象,而不是1对象,因为它与使用b[0][0] = 99访问的list相同。很简单,哈;)

代码语言:javascript
复制
id(a[0]) == id(b[0])
#True !!!

没错,因为虽然我们更改了a[0]引用的内容,但并没有在a[0]b[0]中更改引用本身--这更接近维基百科文章在“浅拷贝”一节中描述的内容。

票数 5
EN

Stack Overflow用户

发布于 2013-08-16 02:48:39

但是为什么写入索引"b“会更改id。

因为它们现在不同了。如果要检查aa[0]仍然是1而不是99,因为b是一个副本。如果您不想要这种行为,就不会执行以下复制:

代码语言:javascript
复制
>>> a = [1,2,3]
>>> b = a
>>> b[0] = 99
>>> a[0]
99

相反,你有这样一个:

代码语言:javascript
复制
>>> a = [1,2,3]
>>> b = a[:]
>>> b[0] = 99
>>> a[0]
1

由于您标记了deepcopy.只有当列表本身包含可变参数时,这才是重要的。比如说,你有:

代码语言:javascript
复制
>>> from copy import deepcopy
>>> a = [[1,2],[3,4]]
>>> b = a
>>> c = a[:]
>>> d = deepcopy(a)

所以abc是浅拷贝,d是深拷贝。

代码语言:javascript
复制
>>> b[0] = 3
>>> a
[3, [3,4]]
>>> c
[[1,2], [3,4]]
>>> d
[[1,2], [3,4]]

ba相同,但副本没有受到影响。

代码语言:javascript
复制
>>> c[1][1] = 'hi'
>>> a
[3, [3, 'hi']]
>>> c
[[1, 2], [3, 'hi']]

如果您替换了c的条目,则a不受影响。但是,如果条目中仍然有原始列表,那么修改其中一个仍然会出现在另一个条目中。嵌套列表仍然相同。

代码语言:javascript
复制
>>> d[1][1] = 10
>>> a
[3, [3, 'hi']]
>>> d
[[1, 2], [3, 10]]

因为d是一个深拷贝,它复制了列表以及嵌套的列表,所以我们可以随意修改它和它的元素,而不必担心其他副本的混乱。

票数 1
EN

Stack Overflow用户

发布于 2013-08-16 03:42:22

当您将a的浅拷贝复制到b ( b = a[:] )时,您会复制它。b在特定的时间点变成了a的副本--它是一个“快照”。

当您更新b[0] = 99时,您更新了b -- a的副本。你没有更新a。这就是做一个浅拷贝(或深拷贝)的意义--你想要一个具有相同内容的新变量,这样你就可以在不影响原始副本的情况下对拷贝进行修改。

如果您希望b[0] = 99也影响a,那么您不想“复制”a,您只想用另一个名称引用它。你会用b = a

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18264983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档