【python】 一文弄懂浅拷贝与深拷贝

系统 1483 0

一、可变对象与非可变对象

  想要理解浅拷贝与深拷贝就必须得先明白可变对象与非可变对象。

  可变对象有: list ,dict ,set

        不可变对象有:int ,float ,bool ,str ,tuple 。

  两者区别:对于可变对象,其值改变是在原地址上操作,不会创建新的内存地址。对于不可变对象其值改变是直接创建新的内存地址。

二、赋值操作符‘=’表示对象的引用。

python里面的 赋值操作符‘=’实际上是对象的引用,其并没有进行复制操作。如果如果赋值操作符右边的操作数是字面值,比如字符串或者数字,那么左边的操作数被设为一个对象的引用,该对象将指向存放字面值得内存对象。(a=1,a指向1的内存对象)。如果右边的操作数是一个对象引用,那么左边的操作数将设置为一个对象引用,并与右边的操作数是一个对象引用,并与右边的操作数指向相同的对象。(b=a,则a,b均指向1的内存对象)

            
              >>> a=1       #a引用对象1(指向1的地址)
>>> b=a       # b引用对象a实际上也是引用对象1  (b指向1的地址)
>>> id(a)     
94474006287136
>>> id(b)
94474006287136
>>> a=2           #a引用对象2,由于对象2相对对象1发生了改变,则重新创建新的内存里面                    存的是对象2 (a指向2处的地址)
>>> id(a)
94474006287168
>>> id(b)       # b继续引用之前的对象1 (b还是指向之前1的地址不变)
94474006287136
>>> 
>>> a=[1,2,3,4]
>>> b=a
>>> b
[1, 2, 3, 4]
>>> a.append(5)
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]

            
          

由上可以发现列表a赋值给b时,实际上a和b都指向同一内存地址。由于列表a是可变对象,对a进行append操作后是在原地址上操作,所以b也跟着改变了。

二、 浅拷贝 copy.copy()

  1.对于不可变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。

            
              >>> a='hello world'
>>> b=a
>>> id(a)
140620341876400
>>> id(b)
140620341876400
>>> c=copy.copy(a)
>>> c
'hello world'
>>> id(c)
140620341876400
>>> 

            
          

对于下面的情况:将a的地址指向改变下,但是b和c的地址仍然不变,指向原来的地址。

            
              >>> a=5   # 将a的地址指向由‘hello world'改为指向5
>>> id(a)
94474006287264
>>> id(b)
140620341876400
>>> id(c)
140620341876400
>>> 

            
          

  2.对于可变类型 List、Dictionary、Set,浅复制会开辟新的内存存放其指向的地址(仅仅是最顶层开辟了新的内存,里层的元素地址还是一样的)

            
              >>> a=[1,2,3,[4,5,6],7,8]   #列表中子对象(子列表[4,5,6])
>>> b=a
>>> c=copy.copy(a)
>>> id(a)        
140620341875976
>>> id(b)
140620341875976
>>> id(c)           # 浅copy 外层开辟新的内存,c的内存地址与a不一样
140620341876104
>>> id(a[3])         # 里层的内存地址
140620341814920
>>> id(d[3])
140620341875720
>>> id(c[3])         # 浅拷贝后的里层的内存地址与原对象的里层内存地址一样。里层在浅copy时                 作为公共部分使用,浅拷贝时这部分不会重新创建新的内存
140620341814920

            
          

  3. 可变类型 (只有可变类型才能对应后面的改变)浅拷贝后, 改变 原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。

            
              >>> a=[1,2,3,{'a':'A'}]
>>> c=copy.copy(a)
>>> id(a)
140620341875976
>>> id(c)
140620341680264
>>> a[0]=0
>>> a
[0, 2, 3, {'a': 'A'}]
>>> c
[1, 2, 3, {'a': 'A'}]
>>> id(a[0])
94474006287104
>>> id(c[0])
94474006287136
>>> a[3]['a']='AAA'
>>> a
[0, 2, 3, {'a': 'AAA'}]
>>> c
[1, 2, 3, {'a': 'AAA'}]
>>> id(a[3])
140620366602104
>>> id(c[3])
140620366602104
>>> 

            
          

  总结:浅拷贝(复制) 只是拷贝了对象引用,而非对象本身。 对于不可变数据,浅拷贝就当于我们所理解的复制,此时也等价于深拷贝。对于可变数据类型,其元素是不可变时与上述一样,如果是可变元素时, 比如列表中有嵌套列表,嵌套列表的引用也被复制,当嵌套列表改变时,其内存地址不变即浅拷贝后其嵌套列表也是跟着变得。

三、深拷贝copy.deepcopy()

        深拷贝就是通常我们所理解的,完全的拷贝并重新创建新的内存空间(包括外层和里层)。

            
              >>> a=[1,2,3,[4,5,6]]
>>> b=copy.deepcopy(a)
>>> id(a)
140620341875976
>>> id(b)
140620341876104
>>> a[3][0]=0
>>> a
[1, 2, 3, [0, 5, 6]]
>>> b
[1, 2, 3, [4, 5, 6]]

            
          

四、其他等价的浅拷贝。

       除了浅拷贝copy.copy外,对于列表还是其他的操作等价于浅拷贝。比如切片和类型名作为函数。

【python】 一文弄懂浅拷贝与深拷贝_第1张图片

使用类型名作为函数的还有如下

copy_of_dict=dict(d)

copt_of_set=set(s)

 


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论