python引用、浅拷贝、深拷贝

在python中,对象的赋值往往是通过“=”进行的。但是由于“=”右边的类型方式不一样,所以产生变量虽然值相同,但是在内存中的地址值不同,可能会造成内存空间的浪费。如题所示,对象赋值中存在三种类型情况的赋值

引用赋值

引用赋值l2=l1 ,首先创建个变量l2,然后在创建一条引用,把这条引用指向l1的地址值。然后l1和l2共同使用这一块地址值。

当l1进行变化后,l2也跟着变化

l1= ['hello']
l2= l1
print(id(l1),id(l2) ) #1580262888480 1580262888480 
print(l1,l2)            # ['hello']  , ['hello']
print(l1 is l2)           # true

l1.append("word")   
print(l1,l2)            ['hello', 'word'] ['hello', 'word']
print(id(l1),id(l2) )   
print(l1 is l2)            #true

浅拷贝

浅copy后,对象的内存地址,指的不是同一个内存地址。浅copy可以通过    对象.copy() 或者  对象切片截取对象[:]         
      浅拷贝,对于内部的不可变对象,拷贝后,原对象修改后,拷贝对象不修改。
      浅拷贝,对于内部的可变对象,拷贝后,原对象修改,拷贝对象也修改。
浅拷贝创建了新的对象,但是只拷贝了序列的元素,对于元素也是一个序列的情况(即子对象),只复制了对这个序列的引用!
list0=[9,2,3,'4',[4.5,[4.55],4.6]]
list1=list0.copy()  #浅copy,地址值变了 
print(id(list0),id(list1))  # 1199787477320 1199787477256
print(list0,list1)  #[9, 2, 3, '4', [4.5, [4.55], 4.6]] [9, 2, 3, '4', [4.5, [4.55], 4.6]]
list0[0]=0
list0[4][0]=38
list0[4][1].append(4.66)
print(list0,list1)  $ [0, 2, 3, '4', [38, [4.55, 4.66], 4.6]] [9, 2, 3, '4', [38, [4.55, 4.66], 4.6]]

深拷贝

深拷贝 deepcopy()是在另一块地址中创建一个新的变量或容器,
     同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本,已经切断他们之间所有的联系。
      深拷贝 拷贝对象及其子对象,拷贝后原对象做任何变化,copy的对象都不会做变化。
     深拷贝是完完全全的拷贝,把原对象完整地拷贝到了新对象中。
list9=[1,2,'3',[4,[4.5],5],6,7]
list8=copy.deepcopy(list9)
print(id(list8) ,id(list9))
print(list8,list9)
list9[2]=0
list9[3][0]=3.99
list9.append(8)
print(list8,list9)
print(id(list8),id(list9))

 
#  深copy后的对象                            #原对象
2339307915016                                 2339307915080
[1, 2, '3', [4, [4.5], 5], 6, 7]       [1, 2, '3', [4, [4.5], 5], 6, 7]
[1, 2, '3', [4, [4.5], 5], 6, 7]       [1, 2, 0, [3.99, [4.5], 5], 6, 7, 8]
2339307915016                                  2339307915080

关于赋值拷贝,浅拷贝,深拷贝的具体适用场景:

当我们仅仅想适用某个对象的值的时候,我们就应该适用深拷贝,来切断他与原拷贝对象的关系,以免随着拷贝对象的变化而变化,但是从内存方面,又多占用内存空间;

当我们想加深连个对象之间的联系,就应使用“引用”

对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说,因为他们每次创建都是同一个地址值。

 

如果元祖变量只包含原子类型对象,则不能深拷贝。

 

ll=[0,1,2,3,4,5,6,7,8,9]


#为这个列表增加一组可变的子元素
ll.append([888888,99999])
import  copy
from copy import deepcopy

'''
引用赋值,浅copy, 深copy
'''
#分别产生对象的数据

l3=ll               #赋值
l2=ll.copy()             #浅拷贝
l4=deepcopy(ll)           #深copy

#操作:对于不可变的子元素操作
ll.append('10')
l2.append('12')
l3.append('13')  #由于引用赋值时,它还是在原对象上面修改的。所以会追加2次操作
l4.append('14')
print(ll,l2,l3)
print("浅copy的对象是个列表,对于不可变的对象,修改原不可变对象是不受影响的")


#操作:对于可变的子元素操作
ll[-3][0]=0

print(ll,l2,l4)  #浅copy和赋值都会改变,深copy不会改变。

print("浅copy的对象是个列表,对于其内部的可变对象,如当前元素是列表下的一个子列表,"
      " 修改它时会随着被copy对象的变化而变化")

'''
所以综上所述:当改变原对象后,想不影响copy后的元素使用,
             第一种方式:使用浅copy时,并且确保里面的元素全部为不可变对象。
              第二种方式:使用deepcopy,但是增加了内存开销。
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值