Python 之 深拷贝和浅拷贝 2

本文详细解析Python中的深拷贝与浅拷贝的区别,并通过代码示例展示了如何使用切片操作、工厂方法及copy模块实现不同类型的拷贝。

  在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。以下分两个思路来分别理解浅拷贝和深拷贝:

  (1)利用切片操作和工厂方法list方法拷贝

  (2)利用copy中的deepcopy方法进行拷贝

1、利用切片操作和工厂方法list方法拷贝

代码场景:有一个小伙jack,tom通过切片操作拷贝jack,anny通过工厂方法拷贝jack。

1
2
3
>>> jack  =  [ 'jack' , [ 'age' 20 ]]
>>> tom  =  jack[:]
>>> anny  =  list (jack)

来看下三者的id值:

1
2
>>>  print  id (jack),  id (tom),  id (anny)
144846988  144977164  144977388

从id值来看,三者是不同的对象。为tom和anny重新命名为各自的名称:

1
2
3
4
>>> tom[ 0 =  'tom'
>>> anny[ 0 =  'anny'
>>>  print  jack, tom, anny
[ 'jack' , [ 'age' 20 ]] [ 'tom' , [ 'age' 20 ]] [ 'anny' , [ 'age' 20 ]]

从这里来看一切正常,可是anny只有18岁,重新为anny定义岁数。

1
2
3
>>> anny[ 1 ][ 1 =  18
>>>  print  jack, tom, anny
[ 'jack' , [ 'age' 18 ]] [ 'tom' , [ 'age' 18 ]] [ 'anny' , [ 'age' 18 ]]

这时候奇怪的事情发生了,jack、tom、anny的岁数都发生了改变,都变成了18了。jack、tom、anny他们应当都是不同的对象,怎么会互相影响呢?看下jack,tom,anny的内部元素每个元素id:

1
2
3
4
5
6
>>> [ id (x)  for  in  jack]
[ 3073896320L 3073777580L ]
>>> [ id (x)  for  in  tom]
[ 144870744 3073777580L ]
>>> [ id (x)  for  in  anny]
[ 144977344 3073777580L ]

 恍然大悟,原来jack、tom、anny的岁数元素指向的是同一个元素。修改了其中一个,当然影响其他人了。那为什么修改名称没影响呢?原来在python中字符串不可以修改,所以在为tom和anny重新命名的时候,会重新创建一个’tom’和’anny’对象,替换旧的’jack’对象。

2、利用copy中的deepcopy方法进行拷贝

为了让他们之间不互相影响,用deepcopy来试试

1
2
3
4
>>> jack  =  [ 'jack' , [ 'age' '20' ]]
>>>  import  copy
>>> tom  =  copy.deepcopy(jack)
>>> anny  =  copy.deepcopy(jack)

根据第一个思路进行重命名,重定岁数操作:

1
2
3
4
5
6
7
>>> tom[ 0 =  'tom'
>>> anny[ 0 =  'anny'
>>>  print  jack, tom, anny
[ 'jack' , [ 'age' '20' ]] [ 'tom' , [ 'age' '20' ]] [ 'anny' , [ 'age' '20' ]]
>>> anny[ 1 ][ 1 =  18
>>>  print  jack, tom, anny
[ 'jack' , [ 'age' '20' ]] [ 'tom' , [ 'age' '20' ]] [ 'anny' , [ 'age' 18 ]]

这时候他们之间就不会互相影响了。打印出每个人的内部元素每个id:

1
2
3
4
5
6
>>> [ id (x)  for  in  jack]
[ 139132064 3073507244L ]
>>> [ id (x)  for  in  tom]
[ 139137464 139132204 ]
>>> [ id (x)  for  in  anny]
[ 139141632 139157548 ]

他们的内部元素也都指向了不同的对象。

3 以上讨论基于List中的List对象进行,那么对于自定义class呢,下面有一段代码供参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import  copy
class  test:
     i = 12
     def  __init__ ( self ):
         self .i = 15          
if  __name__ = = '__main__' :
      t = test()   
      t1 = test()
      a = []
      a.append(t)
      a.append(t1)
      b = a.copy()
      c = copy.deepcopy(a)
      print (a[ 0 ].i,a[ 1 ].i,b[ 0 ].i,b[ 1 ].i,c[ 0 ].i,c[ 1 ].i)
      t.i = 14
      t1.i = 16
      print (a[ 0 ].i,a[ 1 ].i,b[ 0 ].i,b[ 1 ].i,c[ 0 ].i,c[ 1 ].i)

运行结果:

1
2
15 15 15 15 15 15
14 16 14 16 15 15

通过对自定义class的object测试发现,浅拷贝只是对List中对象的引用的拷贝,深拷贝则按照对象进行完整拷贝。

小结:

思路一:利用切片操作和工厂方法list方法拷贝就叫浅拷贝,只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。

思路二:利用copy中的deepcopy方法进行拷贝就叫做深拷贝,外围和内部元素都进行了拷贝对象本身,而不是引用。

但是对于数字,字符串和其他原子类型对象等,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。


原文地址:

文章转载自:[169IT-最新最全的IT资讯]
本文标题:python中的深拷贝(deepcopy)和浅拷贝(copy)介绍及代码参考

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值