Python:使用copy模块深拷贝对象

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

时间: 2024-12-30 21:27:27

Python:使用copy模块深拷贝对象的相关文章

python之copy模块与深拷贝、浅拷贝

copy模块 使用copy模块来实现复制功能. 复制方法分为浅拷贝与深拷贝: 浅拷贝, copy.copy(object) 对内存地址进行复制,目标对象和源对象指向同一内存片内存空间. 深拷贝, copy.deepcopy(object) 为复制生成的对象也申请一个单独的内存空间,内存地址是自主分配的. 完成复制后,目标对象和源对象虽然存储数据是一样的,但是内存地址不同. 两个对象互不干涉. 例: >>> jack = ['jack', ['age', '20']]>>>

python(41):copy拷贝(深拷贝deepcopy与浅拷贝copy)

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1.copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2.copy.deepcopy 深拷贝 拷贝对象及其子对象 >>> import copy >>> a = [1,2,3,4,['a','b']] #原始对象 >>> b = a #赋值,传对象的引用 >>> c = copy.copy(a) >>&g

python之copy模块与深、浅拷贝

copy模块 使用copy模块来实现复制功能. 复制方法分为浅拷贝与深拷贝: 浅拷贝, copy.copy(object) 对内存地址进行复制,目标对象和源对象指向同一内存片内存空间. 深拷贝, copy.deepcopy(object) 为复制生成的对象也申请一个单独的内存空间,内存地址是自主分配的. 完成复制后,目标对象和源对象虽然存储数据是一样的,但是内存地址不同. 两个对象互不干涉. 例: >>> jack = ['jack', ['age', '20']]>>>

Python浅拷贝copy()与深拷贝deepcopy()区别

其实呢,浅拷贝copy()与深拷贝deepcopy()之间的区分必须要涉及到python对于数据的存储方式. 首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变.这就和我们寻常意义上的复制有所不同了. 对于简单的 object,

#python基础学习模块:marshal 对象的序列化

#标准库地址:https://docs.python.org/2/library/marshal.html"""有时候,要把内存中一个对象持久化保存磁盘或者序列化二进制流通过网络发送到远程主机上,python有很多模块提供了序列化与反列化功能,如:marshal, pickle, cPickle等 注意: marshal并不是一个通用的模块,在某些时候它是一个不被推荐使用的模块,因为使用marshal序列化的二进制数据格式还没有文档化,在不同版本的Python中,marsha

python中copy模块

import copyperson = ['name',['saving',100]]#浅copy三种方式p1 = copy.copy(person)p2 = person[:]p3 = list(person) 结果 ['name',['saving',100]] 浅copy的用处: import copyperson = ['name',['saving',100]]p1 = person[:]p2 = person[:]p1[0] = 'husband'p2[0] = 'wife'p1[1

python copy模块

python copy模块 copy模块用于对象的拷贝操作 该模块只提供了两个主要的方法: copy.copy:浅复制 copy.deepcopy:深复制 直接赋值,深拷贝和浅拷贝的区别 直接赋值:简单地拷贝对象的引用,两个对象的id相同.就是对象的引用(别名),就是给当前内存中的对象增加一个“标签”而已.通过使用内置函数 id() ,可以看出指向内存中同一个对象. 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象.即浅复制只复制对象本身,没有复制该对象所引用的对象.A shallow

python学习之copy模块

copy模块中有两个方法,copy.copy()和copy.deepcopy,这两个方法分别是用来实现浅拷贝和深拷贝.所谓浅拷贝就是只拷贝引用,拷贝后生成的两个变量仍然是同一个对象,即其中一个变化了,另一个也跟着变化.而对于深拷贝,则是拷贝数据,生成的两个变量是不同的对象,他们之间的变化互不影响.但有一点要注意,copy模块的两个拷贝方法中针对的深浅拷贝说的是待拷贝对象的元素,即不管是copy()方法还是deepcopy()方法,待拷贝对象本身都是深拷贝,生成的是两个不同的对象,举个例子说明:

转载:python中的copy模块(浅复制和深复制)

主要是介绍python中的copy模块. copy模块包括创建复合对象(包括列表.元组.字典和用户定义对象的实例)的深浅复制的函数. ########copy(x)########创建新的复合对象并通过引用复制x的成员来创建x的浅复制.更加深层次说,它复制了对象,但对于对象中的元素,依然使用引用.对于内置类型,此函数并不经常使用.而是使用诸如list(x), dict(x), set(x)等调用方式来创建x的浅复制,要知道像这样直接使用类型名显然比使用copy()快很多.但是它们达到的效果是一样