图解:python中的浅拷贝和深拷贝
首先,我们考虑这样一个场景:在该场景中,我们各种列表的颜色,每个颜色代表假定颜色类的一个实例。比如,由一个warmtones列表表示现有的颜色,warmtones = list(''red","green","blue")
;
如图所示:
我们希望创建一个名为palette的新列表,复制一份warmtones列表。不过,我们可以在palette中添加额外的颜色,或修改、删除一些现有的颜色,而不影响warmtones的内容。
如果我们这样做:
patette = warmtones,就创建了一个别名,如图所示:
如果在palette中添加或删除颜色,会修改warmtones中的值。
代码演示:
warmtones = ["Red","Green","Blue"]
palette = warmtones
print(id(warmtones))
print(id(palette))
palette.append("Pink")
print(palette)
print(warmtones)
输出结果:
如果我们换一种方式,用list语法创建
palette = list(warmtones)
在这种情况下,我们显式调用列表构造函数,将第一个列表作为参数,这会导致一个新的列表被创建,如图所示,这种就被称为 浅拷贝
在这一种情况中,我们可以合理地从palette添加或删除元素而不影响warmtones。
代码实例:
warmtones = ["Red","Green","Blue"]
palette = list(warmtones)
print(id(warmtones))
print(id(palette))
palette.append("Pink")
print('==========================')
print(id(palette[1]))
print(id(warmtones[1]))
print('=====================')
print(palette)
print(warmtones)
显示效果:
可见,虽然warmtones和palette的地址不一样了,但是它们列表中的元素还是指向同一个地址。
但是,如果是这样情况下,warmtones的其中有一个列表元素的话,情况就不一样了
代码实例:
warmtones = ["Red","Green",["Blue","Orange"]]
palette = list(warmtones)
print(id(warmtones))
print(id(palette))
print('=====================')
palette[2].append("Yellow")
print(palette)
print(warmtones)
结果:
当对palette[2]中的列表作拓展操作时,warmtones[2]的列表也发生改变
我们更希望palette是warmtones的深拷贝(拷贝,包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
)。在深拷贝中,新副本引用的对象也是从原始版本中复制过来的。
图片演示:
python中的copy模块:
该模块提供两个函数:copy函数和deepcopy函数。copy函数创建对象的浅拷贝,deepcopy函数创建对象的深拷贝。
我们用深拷贝来重新编写一下上面的代码:
import copy
warmtones = ["Red","Green",["Blue","Orange"]]
palette = copy.deepcopy(warmtones)
print(id(warmtones))
print(id(palette))
print('=====================')
print(id(palette[1]))
print(id(warmtones[1]))
print('=====================')
palette[2].append("Yellow")
print(palette)
print(warmtones)
结果显示:
发现,现在对palette[2]作append操作,warmtones就不会发生变换了