深浅拷贝

(import copy)

赋值

对象赋值实际上是简单的对象引用。

也就是说,当你创建一个对象,然后把它赋给另一个变量的时候,Python并没有拷贝这个对象,而是拷贝了这个对象的引用。

​例如:

foo1=1.0

foo2=foo1

用操作符is判断时,你可以发现结果是true,是因为python是先创建了一个对象1.0,然后这个对象的引用又被赋值给了foo1和foo2,但是如果是这样:

foo1=1.0

foo2=1.0

这时你会发现,这其实是创建了两个不同的对象,用id()可以发现,二者的地址不同;

其实python还有一个特例,例如:

a=1

b=1

id(a)=id(b),原因是python认为这些小整型是会经常用到的,所以python会缓存一部分小整型。

浅拷贝

序列类型的可以通过三种方式实现浅拷贝,浅拷贝也是默认的拷贝类型:

(1)完全切片操作;([:])

(2)利用工厂函数,比如list(),dict()等;

(3)使用copy模块中的copy()函数。

(然而对于非容器类型没有拷贝这这一说)

用is来看返回0,用==来看返回1。

​赋值的结果是他们的身份相同,但是浅拷贝的身份却不同。

​“对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是”

​例:

(这个例子是借用银行账户的案例来讲的)​

>>> import copy

>>> person=['name',['saveing',100]]

>>> wife=person[:]

>>> hubb=list(person)

>>> id(person)

43752544

>>> id(wife)

43754120

>>> id(hubb)

43533816

>>> [id(x) for x in hubb]

[2434208, 43752664]

>>> [id(x) for x in wife]

[2434208, 43752664]


>>> hubb[1][1]=100

>>> hubb

['name', ['saveing', 100]]

>>> person

['name', ['saveing', 100]]

>>> wife

['name', ['saveing', 100]]

>>> id(hubb)

43533816

>>> id(person)

43752544

>>> id(wife)

43754120


>>> hubb[0]='asd'

>>> hubb

['asd', ['saveing', 100]]

>>> person

['name', ['saveing', 100]]

​>>> wife

['name', ['saveing', 100]]

>>> id(hubb)

43533816

>>> id(person)

43752544

>>> id(wife)

43754120

第1个对象是不可变的(是个字符串类型),而第2个是可变的(一个列表)。正因为如此,当进行浅拷贝时,字符串被显式的拷贝,并新创建了一个字符串对象,而列表元素只是把它的引用复制了一下,并不是它的成员。

假设我们要创建一个联合账户,那这是一个非常棒的方案。但是,如果需要的是两个分离账户,就需要作些改动了。

深拷贝​

要得到一个完全拷贝或者说深拷贝——创建一个新的容器对象,包含原有对象元素(引用)全新拷贝的引用——需要copy.deepcopy()函数。​

例:​

>>> import copy​

>>> person = ['name', ['savings', 100.00]]

​>>> hubb = person

​>>> wife = copy.deepcopy(person)

​>>> [id(x) for x in person, hubb, wife]

​[12242056, 12242056, 12224232]

​>>> hubb[0] = 'joe'

​>>> wife[0] = 'jane'

​>>> hubb, wife

​(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])

​>>> hubb[1][1] = 50.00

​>>> hubb, wife

​(['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])​

>>> [id(x) for x in hubb]

[12191712, 11826280]

>>> [id(x) for x in wife]

[12114080, 12224792]​

注意:

>>> person = ['name', ('savings', 100.00)]

>>> newPerson = copy.deepcopy(person)

>>> [id(x) for x in person, newPerson]

[12225352, 12226112]

>>> [id(x) for x in person]

[9919616, 11800088]

>>> [id(x) for x in newPerson]

[9919616, 11800088]

(上下部分的地址反映出深拷贝会改变副本的id,而对于其中元素则是id不变,如有改动,就会改变)

以下有几点关于拷贝操作的注意:

第一,非容器类型(比如数字、字符串和其他“原子”类型的对象,像代码、类型和xrange对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的。

第二,如果元组变量只包含原子类型对象,对它的深拷贝将不会进行。如果我们把账户信息改成元组类型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝。

第三,并不是所有的对象都可以安全的复制,例如具有开放式连接的套接字复制到远程计算机就不会执行,这是由于对象的部分内部状态(开放式连接)​位于python的领域之外。文件对象是禁止复制领域中的另一个示例。​

核心模块:copy

​我们刚才描述的浅拷贝和深拷贝操作都可以在copy模块中找到。

其实copy模块中只有两个函数可用:

copy()进行浅拷贝操作;

deepcopy()进行深拷贝操作。​

​import copy

        x = copy.copy(y)        # make a shallow copy of y

        x = copy.deepcopy(y)    # make a deep copy of y

​(来自帮助文档)


资料来源:

《Python 2.1 宝典》

http://book.51cto.com/art/200806/77233.htm(6.20 *拷贝Python对象、浅拷贝和深拷贝)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值