浅复制,也就是copy,指的是创建一个对象以指向原有对象中各元素的地址。
>>> from copy import copy, deepcopy
>>> old_instance = ['copyme', [1, 2, 3]]
>>> new_instance = copy(old_instance)
>>> [id(i) for i in old_instance]
[48374208, 48698272]
>>> [id(i) for i in new_instance]
[48374208, 48698272]
可以看到,我们创建了一个new_instance来接收浅复制返回的old_instance,其new_instance中各元素的地址与old_instance中对应元素相同。
当我们试图修改old_instance中可变元素的值时,会相应地反映在new_instance中:
>>> old_instance[1][0] = 4
>>> old_instance
['copyme', [4, 2, 3]]
>>> new_instance
['copyme', [4, 2, 3]]
请注意字符串和元组是不可变元素!当我们试图修改字符串时,必然会引发异常:
>>> old_instance[0][4:] = ''
Traceback (most recent call last):
File "", line 1, in
TypeError: 'str' object does not support item assignment
但我们可以将这个元素的地址指向其他字符串对象,以达到”修改“字符串的目的:
>>> old_instance[0] = 'copyyou'
>>> old_instance
['copyyou', [4, 2, 3]]
>>> new_instance
['copyme', [4, 2, 3]]
明显地可以观察到,new_instance[0]仍然指向原来字符串的地址,并没有跟随着old_instance[0]指向新的字符串对象,这是因为我们将[0]元素的地址指向了新的字符串对象,而非在原地址上修改对象。故上述修改添加引号。可自行使用id函数检查地址变化。
请注意这点特性!
深复制,将要复制的对象复制到其他内存地址上,实际上是创建一个副本,对原有对象的变动不会影响到副本。
>>> old_instance = ['copyme', [1, 2, 3]]
>>> new_instance = deepcopy(old_instance)
>>> new_instance
['copyme', [1, 2, 3]]
>>> [id(x) for x in old_instance]
[48374208, 48699232]
>>> [id(x) for x in new_instance]
[48374208, 48699152]
可以看到,嵌套列表中的内层列表的地址已经不同。而字符串的地址相同,这是因为字符串是不可变对象,没有必要为其再开辟新的地址空间存储一份副本。
深复制的新对象在新地址不跟随原对象在原地址的变动:
>>> old_instance[1][0] = 4
>>> old_instance
['copyme', [4, 2, 3]]
>>> new_instance
['copyme', [1, 2, 3]]
也适用于嵌套结构:
>>> inner = [6, 6, 6]
>>> old_instance = [9, 9, 9, inner]
>>> new_instance = deepcopy(old_instance)
>>> old_instance
[9, 9, 9, [6, 6, 6]]
>>> new_instance
[9, 9, 9, [6, 6, 6]]
>>> [id(x) for x in old_instance]
[1507470608, 1507470608, 1507470608, 48736096]
>>> [id(x) for x in new_instance]
[1507470608, 1507470608, 1507470608, 48699032]
>>> inner[0] = 9
>>> old_instance
[9, 9, 9, [9, 6, 6]]
>>> new_instance
[9, 9, 9, [6, 6, 6]]