先來看一下淺復(fù)制和深復(fù)制的基本概念。
淺復(fù)制是指當(dāng)對象的字段值被復(fù)制時,字段引用的對象不會被復(fù)制。
深復(fù)制是指對對象事例中字段引用的對象也進(jìn)行復(fù)制的一種方式。
在Python中默認(rèn)是做淺復(fù)制,比如說使用內(nèi)置的類型構(gòu)造方法或[:]復(fù)制列表。如果所有元素是不可變的,那么這樣操作沒有問題,但是如果有可變元素就會導(dǎo)致意想不到的問題,下面通過一個例子來演示一下。
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1) # l1 和 l2 指代不同的列表,但是二者引用同一個列表 [66, 55, 44] 和元組 (7, 8, 9)
l1.append(100) # 把 100 追加到 l1 中,對 l2 沒有影響。
l1[1].remove(55) # 移除l1[1]中的55,這對l2有影響,因?yàn)閘1[1]和l2[1]指向同一個列表
print('l1:', l1)
print('l2:', l2)
l2[1] += [33, 22] # +=運(yùn)算符就地修改列表,所以這次修改在l1[1]中有影響
l2[2] += (10, 11) # 對于元組, +=運(yùn)算符是創(chuàng)建一個新元組,然后重新綁定給變量l2[2],這對l1[2]沒有影響,l1 和 l2 中最后位置上的元組現(xiàn)在不是同一個對象
print('l1:', l1)
print('l2:', l2)
"""
l1: [3, [66, 44], (7, 8, 9), 100]
l2: [3, [66, 44], (7, 8, 9)]
l1: [3, [66, 44, 33, 22], (7, 8, 9), 100]
l2: [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]
"""
下面使用copy模塊提供的deepcopy和copy函數(shù)為對象進(jìn)行淺復(fù)制和深復(fù)制。
先來創(chuàng)建一個類,該類接受乘客序列,并支持移除一個乘客和增加一個乘客。
class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers)
def pick(self, name):
"""上車"""
self.passengers.append(name)
def drop(self, name):
"""下車"""
self.passengers.remove(name)
下面進(jìn)行測試。
import copy
bus1 = Bus(['Jack', 'Tom', 'Marry'])
# 淺復(fù)制
bus2 = copy.copy(bus1)
# 深復(fù)制
bus3 = copy.deepcopy(bus1)
# 先來查看各對象的id值
print(id(bus1), id(bus2), id(bus3))
# bus1 Marry下車, 觀察bus2和bus3的乘客列表的變化
bus1.drop('Marry')
print(bus2.passengers, bus3.passengers)
# 下面看一下各實(shí)例中乘客列表對象的id值
print(id(bus1.passengers), id(bus2.passengers), id(bus3.passengers))
"""
57602992 57602896 57602864
['Jack', 'Tom'] ['Jack', 'Tom', 'Marry']
60126312 60126312 57575024
"""
從結(jié)果中看出,bus1中的Marry下車,bus2中的Mary也不見了,因?yàn)槭菧\復(fù)制,他們指向同一個對象,但是bus3是深復(fù)制,所以對其沒有什么影響。
另外從各BUS實(shí)例中的passengers的id值能夠更明顯地證明上面所說的。