import copy
class Pizza():
def __init__ (self,name,size,price):
self.name=name
self.size=size
self.price=price
def getPizzaInfo(self):
return self.name,self.size,self.price
def showPizzaInfo(self):
print("Pizza name :"+self.name)
print("Pizza size:"+self.size)
print("Pizza price:"+self.price)
def changeSize(self,size):
self.size=size
def changePrice(self,price):
self.price=price
class Order():
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("customer name:"+self.customername)
for i in self.pizzaList:
i.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 information:")
customer1.getorderdetail()
customer1 order information: 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
程序描述的是客户在Pizza店里下了一个订单,并将具体的订单信息打印出来的场景。 运行输出结果如下:
customer2=copy.copy(customer1)
print("order2 customer name")
order2 customer name
customer2.customername
customer2.changeName("li")
customer2.getPizza(2).changeSize("9")
customer2.getPizza(2).changePrice("30")
print("customer 2 order information:")
customer2.getorderdetail()
customer 2 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也想下一个跟客户1一样的订单,只是要将预定的水果披萨的尺寸和价格进行相应的修改。 于是服务员拷贝了客户的订单信息并做了一定的修改,代码如下;
在修改完客户2的订单信息之后,现在再来检査一下客户1的订单信息:
print("customer1 order information:")
customer1.getorderdetail()
customer1 order information: 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本没要求修改订单的内容,同样的结果必定会直接影响到客户满意度。 问题出现在哪里?这是本节要重点讨论的内容。先来分析客户1和客户2订单内容的关系图,如图所示。
图4-1 客户1和客户2订单的关系示意图
customerl
中的 pizzaList
是一个由 Pizza
对象组成的列表,
其中存放的实际是对一个个具体 Pizza
对象的引用,
在内存中就是一个具体的地址,可以通过査看id得到相关信息。
print(id (customer1 .pizzaList [0]))
139919269902528
print(id (customer1 .pizzaList [1]))
139919269898832
print(id (customer1 .pizzaList [2]))
139919269898976
print(id (customer1.pizzaList))
139919269874688
customer2
的订单通过 copy.copy(customerl)
获得,
通过 id
函数査看 customer2
中 pizzaList
的具体 Pizza
对象你会发现它们和 customerl
中的输出是一样的(读者可以自行验证)。
这是由于通过 copy.copy()
得到的 customer2
是customer1
的一个浅拷贝,
它仅仅拷贝了 pizzalist
里面对象的地址而不对对应地址所指向的具体内容(即具体的 pizza
)进行拷贝,
因此 customer2
中的 pizzaList
所指向的具体内容是和 customer1
中一样的。
所以对pizza fruit的修改直接影响了 customer1
的订单内容。实际上在包含引用的数据结构中,
浅拷贝并不能进行彻底的拷贝,当存在列表、字典等不可变对象的时候,它仅仅拷贝其引用地址。
要解决上述问题需要用到深拷贝,深拷贝不仅拷贝引用也拷贝引用所指向的对象,
因此深拷贝得到的对象和原对象是相互独立的。
上面的例子充分展示了浅拷贝和深拷贝之间的差异,在实际应用中要特別注意这两者之间的区别。
实际上Python copy
模块提供了与浅拷贝和深拷贝对应的两种方法的实现,
通过名字便可以轻易进行区分,模块在拷贝出现异常的时候会拋出 copy.error
。
copy.copy(x) : Return a shallow copy of x.
copy, deepcopy (x) : Return a deep copy of x.
exception copy- error : Raised for module specific errors.
实际上,上面的程序应该将 customer2=copy.copy(customer])
改为 copy.deepcopy()
来实现。