我对浅拷贝和深拷贝中的对象是如何引用的感到困惑

问题描述 投票:0回答:3

浅_复制

foo = [1, 2, []] 
bar = foo.copy() 
foo[0] is bar[0] 
foo[2] is bar[2] 
True 
True 

这是否意味着它们都引用相同的对象? 然而,当我修改它们时,它们的行为有所不同。

bar[0] = 0 
print(foo) 
[1, 2, []] 
bar[-1].append(3)
print(foo) 
[1, 2, [3]] 

如果 foo[0] 和 bar[0] 引用同一个对象,当我修改 bar[0] 时,为什么 foo[0] 保持不变?当我修改 bar[2] 时,foo[2] 发生了变化

深度_复制

foo = [1, 2, []] 
bar = copy.deepcopy(foo)
foo[0] is bar[0] foo[2] is bar[2] 
True 
False 

另外,为什么 foo[2] 和 bar[2] 在这里不引用同一个对象

python python-3.x copy deep-copy shallow-copy
3个回答
1
投票

这里混乱的根本根源是你实际上正在改变哪个对象。以下行:

bar[0] = 0 

变异

bar
,而不是
bar[0]
。另一方面,

bar[-1].append(3)

变异

bar[-1]
,因为
.append
是一种变异方法。

但是如果你做了同样的事情,你会看到相同的行为

>>> foo = [1, 2, []]
>>> bar = foo.copy()
>>> foo[-1] = [3]
>>> foo, bar
([1, 2, [3]], [1, 2, []])
>>>

0
投票

除了评论:

您可以使用

id()
方法查看项目的唯一(身份)id。 “这保证在同时存在的对象中是唯一的”

所以修改成这样的代码会更清晰:

foo = [1, 2, []] 
bar = foo.copy() 
print(foo[0] is bar[0]) 
print(foo[2] is bar[2]) 


print('foo id:', id(foo))
print('bar id:', id(bar))


print('bar[0] id:', id(bar[0]))

print('foo:', foo)

bar[-1].append(3)

print('bar:', bar)

返回这个:

True
True
foo id: 2526001813312
bar id: 2526001811840
bar[0] id: 140706948506408
foo: [1, 2, []]
bar: [1, 2, [3]]

特别是,您现在可以看到 id 是不同的。所以它们实际上是不同的对象。

因此对

bar
的修改不会修改
foo
,反之亦然。

对于深度复制部分,代码需要导入和修改,如下所示,以显示正在发生的情况。

import copy
foo = [1, 2, []] 
bar = copy.deepcopy(foo)
print('foo:', foo)
print('bar:', bar)

print(foo[0] is bar[0]) 
print(foo[2] is bar[2])
print([] is []) 

返回这个:

foo: [1, 2, []]
bar: [1, 2, []]
True
False
False

基本上

foo[2]
bar[2]
是空列表。 我们可以从
print([] is [])
看到我们得到
False

这里是文档的链接: https://docs.python.org/3/library/copy.html#copy.deepcopy


0
投票

您可以使用模块 memory_graph 绘制数据图表,以更好地理解 Python 数据模型:

import memory_graph # see link above for install instructions
import copy

foo = [1, 2, []] 

bar_shallow = foo.copy() 
print( foo[0] is bar_shallow[0] ) # True
print( foo[2] is bar_shallow[2] ) # True

bar_deep = copy.deepcopy(foo)
print( foo[0] is bar_deep[0] ) # True
print( foo[2] is bar_deep[2] ) # False

memory_graph.d() # show the graph

graph of all local variables

结果图表清楚地表明:

  • foo.copy()
    进行浅复制,第一个元素被复制,但底层数据被共享。
  • copy.deepcopy(foo)
    进行深度复制,所有数据都被复制并且没有任何内容被共享。

这解释了为什么

foo[2]
bar_shallow[2]
是相同的列表,但 不是
bar_deep[2]
相同的列表。

完全披露:我是memory_graph的开发者。

© www.soinside.com 2019 - 2024. All rights reserved.