Python語言中有深拷貝和淺拷貝的概念,那什麼是深拷貝,淺拷貝呢?
淺拷貝(shallow copy):構造一個新的複合對象並將從原對象中發現的引用(也就是地址,而不是地址所指向的內容)插入該對象中。淺拷貝的實現方法有很多種,如工廠函數、切片操作、copy模塊中的copy操作。
深拷貝(deep copy):也構造一個新的複合對象,但是遇到引用會繼續遞歸拷貝其所指向的內容,也就是說他會針對引用所指向的對象繼續執行拷貝,因此產生的對象不受其它對象操作的影響。深拷貝的實現需要依賴copy模塊的deepcopy()操作
先看下面例子吧,定義了一個Pizza類和Order類,分別反應Pizza信息和訂單信息
#coding=utf-8 import copy class Pizza(object): """ Pizza類 """ def __init__(self,name,size,price): self.name = name self.size = size self.price = price def showPizzaInfo(self): print "".join(('Pizza name:',self.name)) print "".join(("Pizza size:",str(self.size))) print "".join(('Pizza price:',str(self.price))) #字符串的拼接儘量使用join()函數,不要使用+號,因爲前者效率更高,而且更Pythonnic def getPizzaInfo(self): return self.name,self.size,self.price def changename(self,name): self.name = name def changesize(self,size): self.size = size def changeprice(self,price): self.price = price class Order(object): """ 訂單類 """ def __init__(self,name): self.customername = name self.pizzalist = [] self.pizzalist.append(Pizza("Mushroom",12,30)) def ordermore(self,pizza): self.pizzalist.append(pizza) def changename(self,name): self.customername = name def getorderdetail(self): print "".join(('customer name:',self.customername)) for one in self.pizzalist: one.showPizzaInfo() def getPizza(self,number): return self.pizzalist[number] customer1 = Order("zhang") customer1.ordermore(Pizza("seafood",9,40)) customer1.ordermore(Pizza("fruit",12,35)) print "customer1 order infomation:" customer1.getorderdetail() print "--------------------"
上面代碼描述的意思是客戶1下了一個訂單,並且把具體訂單打印出來的場景。運行結果如下:
customer1 order infomation:
customer name:zhang
Pizza name:Mushroom
Pizza size:12
Pizza price:30
Pizza name:seafood
Pizza size:9
Pizza price:40
Pizza name:fruit
Pizza size:12
Pizza price:35
--------------------
假設客戶2也想跟客戶1下一樣的訂單,只是改變了水果Pizza的尺寸,那麼價格也應該作相應的修改。於是想到拷貝客戶1的訂單信息並做一定的修改,代碼如下:
customer2 = copy.copy(customer1) print "".join(["order2 customer name:",customer2.customername]) customer2.changename("Li") customer2.getPizza(2).changesize(9) customer2.getPizza(2).changeprice(30) print "customer2 order information:" customer2.getorderdetail() print "----------------------"
輸出結果如下:
order2 customer name:zhang
customer2 order information:
customer name:Li
Pizza name:Mushroom
Pizza size:12
Pizza price:30
Pizza name:seafood
Pizza size:9
Pizza price:40
Pizza name:fruit
Pizza size:9
Pizza price:30
可以說還是滿足客戶2的要求的,修改客戶2訂單信息後再來看看客戶1訂單信息,
print "customer1 order infomation:" customer1.getorderdetail() print "----------------------"
結果如下:
customer1 order infomation:
customer name:zhang
Pizza name:Mushroom
Pizza size:12
Pizza price:30
Pizza name:seafood
Pizza size:9
Pizza price:40
Pizza name:fruit
Pizza size:9
Pizza price:30
----------------------
客戶1訂單信息除了客戶姓名外,其它和客戶2訂單信息居然一樣了。如果這真是一個生成用的系統,必將會影響客戶的滿意度,因爲客戶1沒有要求修改訂單信息呀。這怎麼回事呢?
customer1 中的pizzalist是由Pizza對象組成的列表,其中存放的實際是對一個個具體Pizza對象的引用,在內存中就是一個具體的位置,可以打印出它們的id
print id(customer1.pizzalist[0]) print id(customer1.pizzalist[1]) print id(customer1.pizzalist[2]) print id(customer1.pizzalist)
結果如下:
140206506600080
140206506602064
140206506652560
140206507110552
customer2的訂單是由copy.copy(customer1)獲得,把customer2的pizzalist的id打印出來與customer1的pizzalist同時打印出來,代碼如下:
print id(customer1.pizzalist[0]) print id(customer1.pizzalist[1]) print id(customer1.pizzalist[2]) print id(customer1.pizzalist) print "--------------------------" print id(customer2.pizzalist[0]) print id(customer2.pizzalist[1]) print id(customer2.pizzalist[2]) print id(customer2.pizzalist)
打印結果如下
140206506600080
140206506602064
140206506652560
140206507110552
--------------------------
140206506600080
140206506602064
140206506652560
140206507110552
發現是一樣的,這是由於copy.copy()得到的是一個淺拷貝,它僅僅拷貝了對象的地址而不對對應地址所指的具體內容進行拷貝。
包含引用的數據結構中,淺拷貝並不能進行徹底拷貝,當存在字典、列表等可變對象時,它僅僅拷貝了其引用地址,並沒有拷貝對應地址的內容。要解決這個問題就需要使用深拷貝,深拷貝不僅拷貝了引用也拷貝了引用所指向的對象(也就是內容),因此深拷貝得到的對象與原對象是相互獨立的。
如果將上面程序改爲customer2 = copy.deepcopy(customer1)來實現就不會出現這樣的問題。
下面簡單介紹一些copy模塊的一些知識:
copy模塊的主要對外接口就是copy()和deepcopy()。
在定義類的時候,通過定義__copy__和__deepcopy__方法,可以改變copy的默認行爲。下面是一個簡單的例子:
#coding=utf-8 import copy class CopyObj(object): def __repr__(self): return "CopyObj" def __copy__(self): return "copy" obj = CopyObj() obj1 = copy.copy(obj) obj2 = copy.deepcopy(obj) print obj print obj1 print obj2 print "-----------------" class Copyobj(object): def __repr__(self): return "Copyobj" def __deepcopy__(self,meno=None): return "deep copy" a = Copyobj() b = copy.copy(a) c = copy.deepcopy(a) print a print b print c
輸出結果如下:
CopyObj
copy
CopyObj
-----------------
Copyobj
Copyobj
deep copy