Python - 浅拷贝与深拷贝

浅拷贝:构造方法或切片 [:] 做的是浅拷贝(即拷贝了最外层容器,副本中的元素是原容器中元素的引用

在 Python 中,通过一个对象向另外一个对象赋值,实际仅仅是赋值了对象的引用,而非创建一个对象并赋值。那如何真正拷贝对象呢?我们看一下两种不同的拷贝方式。

先从一个示例看起:

>>> Anndy = ['Anndy', ['age', 24]]
>>> Tom = Anndy[:]
>>> Cindy = list(Anndy)
>>>
>>> print id(Anndy), id(Tom), id(Cindy)
56466248 56466440 55883208
>>>
>>> print [id(x) for x in Anndy]
[56517256L, 56414152L]
>>> print [id(x) for x in Tom]
[56517256L, 56414152L]
>>> print [id(x) for x in Cindy]
[56517256L, 56414152L]
>>>
>>> print Anndy, Tom, Cindy
['Anndy', ['age', 24]] ['Anndy', ['age', 24]] ['Anndy', ['age', 24]]

由此可见,是创建了三个不同的对象。但是事实真的是这样吗?让我们修改一下名字和年龄看看。
3个对象的id56466248 56466440 55883208是不一样的,
但是每个对象中名字和年龄的id是相同的,都是[56517256L, 56414152L]

修改名字:

>>> Tom[0]="Tom"
>>> Cindy[0]="Cindy"
>>> print Anndy, Tom , Cindy
['Anndy', ['age', 24]] ['Tom', ['age', 24]] ['Cindy', ['age', 24]]

修改Tom的名字没有任何问题。
修改年龄:
修改Tom的年龄为12岁

>>> Tom[1][1] = 12
>>> print Anndy, Tom , Cindy
['Anndy', ['age', 12]] ['Tom', ['age', 12]] ['Cindy', ['age', 12]]

所有人的年龄都被修改了。这真是恐怖啊,并不是我们想要的结果。为啥会是这样呢?打印一下列表中各个对象的ID看一下:

>>> [id(x) for x in Anndy]
[55599912L, 55496648L]
>>> [id(x) for x in Tom]
[55581392L, 55496648L]
>>> [id(x) for x in Cindy]
[55581952L, 55496648L]

可见,第二个列表的元素是相同的。这是为什么呢?

原因就是浅拷贝

构造方法或切片 [:] 做的是浅拷贝(即拷贝了最外层容器,副本中的元素是原容器中元素的引用)。如果所有元素都是不可变的(比如名字字符串,修改的时候会重新创建对象,仅仅包括原子对象的元组也属于这种情况),那么这样没有问题,还能节省内存。但是,如果有可变的元素,可能就会导致意想不到的问题,正如刚刚,修改一个人的年龄,所有人的年龄都发生了变化。

那么现在来看一下深拷贝。深拷贝,顾名思义,深层次的拷贝,不仅仅拷贝最外层容器,还会拷贝容器中的元素。这是利用copy中的deepcopy方法来实现的。
实现如下:

深拷贝

import copy

Anndy = ['Anndy', ['age', 24]]
Tom = copy.deepcopy(Anndy)
Cindy = copy.deepcopy(Anndy)

打印id,名字的id全是一样的,但年龄的不一样了

>>> print [id(x) for x in Anndy]
[56517256L, 56414152L]
>>> print [id(x) for x in Tom]
[56517256L, 56502600L]
>>> print [id(x) for x in Cindy]
[56517256L, 56502216L]

修改名字

Tom[0] = 'Tom'
Cindy[0] = 'Cindy'

打印id;名字的id改变了,但是修改Tom的名字不会影响其他人的

>>> print [id(x) for x in Anndy]
[56517256L, 56414152L]
>>> print [id(x) for x in Tom]
[56498736L, 56502600L]
>>> print [id(x) for x in Cindy]
[56499296L, 56502216L]
>>> print Anndy, Tom, Cindy
['Anndy', ['age', 24]] ['Tom', ['age', 24]] ['Cindy', ['age', 24]]

修改年龄

Tom[1][1] = 12

打印id和数据;修改Tom的年龄,不会影响其他人的年龄。

>>> print [id(x) for x in Anndy]
[56517256L, 56414152L]
>>> print [id(x) for x in Tom]
[56498736L, 56502600L]
>>> print [id(x) for x in Cindy]
[56499296L, 56502216L]
>>> print Anndy, Tom, Cindy
['Anndy', ['age', 24]] ['Tom', ['age', 12]] ['Cindy', ['age', 24]]

仅仅修改了Tom的年龄,Anndy和Cindy的没有被修改。

仅仅是Tom的年龄被修改了。另外,还是需要注意一下,对于不可变的对象,比如字符串,比如包括原子对象的元组,对其深拷贝不会进行

参考并感谢

猜你喜欢

转载自blog.csdn.net/wang725/article/details/81270025