python基础 — 赋值,浅拷贝,深拷贝

一、可变对象和不可变对象

先来了解两个重要的概念:

  • 可变对象:对象的值发生变化,内存地址不变。常见的有list, set, dict
  • 不可变对象:对象的值发生变化,内存地址改变。常见的有int, float,string,tuple

为了弄明白赋值,浅拷贝,深拷贝的差异,下面将通过实例来分析。

二、赋值

1、 可变对象

# 可变对象
obj = [1, 2, 3]
a = obj

print("原对象obj:", obj, id(obj))
print("赋值对象a:", a, id(a))

------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3] 2211245785600
赋值对象a: [1, 2, 3] 2211245785600

分析运行结果可知,赋值对象a跟原对象obj的值相同,内存地址相同。

(1)如果对象obj发生改变,赋值的对象a会发生怎样的变化?

# 可变对象
obj = [1, 2, 3]
a = obj

print("原对象obj:", obj, id(obj))
print("赋值对象a:", a, id(a))

print("修改对象obj后:")
obj.append(4)
print("原对象obj:", obj, id(obj))
print("赋值对象a:", a, id(a))

------------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3] 1896687337984
赋值对象a: [1, 2, 3] 1896687337984
修改对象obj后:
原对象obj: [1, 2, 3, 4] 1896687337984
赋值对象a: [1, 2, 3, 4] 1896687337984

分析运行结果可知,原对象obj的值发生改变后,赋值对象a的值也跟着改变了,但是他们的内存地址并不会改变。

2、不可变对象

# 不可变对象
obj = (1, 2, 3)
a = obj

print("原对象obj:", obj, id(obj))
print("赋值对象a:", a, id(a))

---------------------------------------------------------------------------------
运行结果:
原对象obj: (1, 2, 3) 2408442060864
赋值对象a: (1, 2, 3) 2408442060864

分析运行结果可知,赋值对象a跟原对象obj的值相同,内存地址相同。

小结:

赋值只是创建了一个原对象的引用对象,并不会开辟新的内存地址。

原对象发生改变,赋值对象的值也会同步变化,内存地址不变。

 

三、浅拷贝(copy)

1、可变对象

import copy

# 可变对象
obj = [1, 2, 3]
b = copy.copy(obj)

print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

------------------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3] 2723109220736
浅拷贝对象b: [1, 2, 3] 2723109272512

分析运行结果可知,对于可变对象,浅拷贝对象b的内存地址和原对象obj的内存地址不一致,浅拷贝开辟了新的内存地址。

(1)如果对象obj发生改变,浅拷贝对象b会发生怎样的变化?

import copy

# 可变对象
obj = [1, 2, 3]
b = copy.copy(obj)

print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

print("修改对象obj后:")
obj.append(4)
print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

----------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3] 2065559531904
浅拷贝对象b: [1, 2, 3] 2065559583680
修改对象obj后:
原对象obj: [1, 2, 3, 4] 2065559531904
浅拷贝对象b: [1, 2, 3] 2065559583680

分析运行结果可知,原对象obj的值发生改变后,浅拷贝对象b的值和内存地址并不会受到影像。

(2)如果可变对象obj是一个嵌套结构呢?

import copy

# 可变对象,嵌套结构
obj1 = [1, 2]
obj = [1, 2, 3, obj1]
b = copy.copy(obj)

print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

print("修改父对象obj,子对象obj1后:")
obj1.append(3)
obj[0] = 'a'
print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

-------------------------------------------------
运行结果:
原对象obj: [1, 2, 3, [1, 2]] 2545761713280
浅拷贝对象b: [1, 2, 3, [1, 2]] 2545761711744
修改父对象obj,子对象obj1后:
原对象obj: ['a', 2, 3, [1, 2, 3]] 2545761713280
浅拷贝对象b: [1, 2, 3, [1, 2, 3]] 2545761711744

分析运行结果可知,对于包含了嵌套结构的可变对象。

父对象obj发生改变后,浅拷贝对象b不会受到影响,值和内存地址都不变。

子对象obj1发生改变后,浅拷贝对象b的子元素[1,2]也跟着变成了[1,2,3],内存地址不变。

小结:

对于可变对象,浅拷贝只拷贝父对象,开辟新的内存地址。不拷贝子对象,只是引用了子对象。

2、不可变对象

import copy

# 不可变对象
obj = (1, 2, 3)
b = copy.copy(obj)

print("原对象obj:", obj, id(obj))
print("浅拷贝对象b:", b, id(b))

----------------------------------------------------------------------------------
运行结果:
原对象obj: (1, 2, 3) 2442259410880
浅拷贝对象b: (1, 2, 3) 2442259410880

分析运行结果可知,对于不可变对象,浅拷贝只是地址的引用,并不会开辟新的内存地址。

四、深拷贝(deepcopy)

1、可变对象

import copy

# 可变对象
obj = [1, 2, 3]
c = copy.deepcopy(obj)

print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

------------------------------------------------------------------------
运行结果:

原对象obj: [1, 2, 3] 2616267190656
深拷贝对象c: [1, 2, 3] 2616267242368

分析运行结果可知,对于可变对象,深拷贝会开辟新的内存地址。

(1))如果对象obj发生改变,深拷贝对象c会发生怎样的变化?

import copy

# 可变对象
obj = [1, 2, 3]
c = copy.deepcopy(obj)

print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

print("修改原对象obj后:")
obj[0] = 'a'
print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

----------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3] 2451928592704
深拷贝对象c: [1, 2, 3] 2451928644480
修改原对象obj后:
原对象obj: ['a', 2, 3] 2451928592704
深拷贝对象c: [1, 2, 3] 2451928644480

分析运行结果可知,原对象obj的值发生改变后,深拷贝对象的值和内存地址并不会受到影像。

(2)如果可变对象obj是一个嵌套结构呢?

import copy

# 可变对象
obj1 = [1,2]
obj = [1, 2, 3,obj1]
c = copy.deepcopy(obj)

print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

print("修改父对象obj,子对象obj1后:")
obj1.append(3)
obj[0] = 'a'
print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

--------------------------------------------------------------------------
运行结果:
原对象obj: [1, 2, 3, [1, 2]] 1690664172288
深拷贝对象c: [1, 2, 3, [1, 2]] 1690664170816
修改父对象obj,子对象obj1后:
原对象obj: ['a', 2, 3, [1, 2, 3]] 1690664172288
深拷贝对象c: [1, 2, 3, [1, 2]] 1690664170816

分析运行结果可知,对于包含了嵌套结构的可变对象。

父对象obj发生改变后,深拷贝对象c不会受到影响,值和内存地址都不变。

子对象obj1发生改变后,深拷贝对象c不会受到影响,值和内存地址都不变。

小结:

对于可变对象,深拷贝会拷贝父对象和所有的子对象,开辟新的内存地址。

2、不可变对象

import copy

# 不可变对象

obj = (1,2,3)
c = copy.deepcopy(obj)

print("原对象obj:", obj, id(obj))
print("深拷贝对象c:", c, id(c))

------------------------------------------------------------------------------
运行结果:
原对象obj: (1, 2, 3) 2928533385024
深拷贝对象c: (1, 2, 3) 2928533385024

分析运行结果可知,对于不可变对象,深拷贝只是地址的引用,并不会开辟新的内存地址。

五、总结

赋值:

赋值只是创建了一个原对象的引用对象,并不会开辟新的内存地址。

原对象发生改变,赋值对象的值也会同步变化,内存地址不变。

浅拷贝:

对于可变对象,浅拷贝只拷贝父对象,开辟新的内存地址。不拷贝子对象,只是引用了子对象。

对于不可变对象,浅拷贝只是地址的引用,并不会开辟新的内存地址。

深拷贝:

对于可变对象,深拷贝会拷贝父对象和所有的子对象,开辟新的内存地址。

对于不可变对象,深拷贝只是地址的引用,并不会开辟新的内存地址。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值