python 赋值/浅拷贝/深拷贝的区别

2023-11-19

在了解赋值/浅拷贝/深拷贝之前,需要预热一下python对象知识点。

一.变量名字和对象

a = 123
b = [1,2,3]

代码中,a和b是变量名称,123和[1,2,3]是对象,对象包括值和类型。
python中,一切皆对象,对象占内存,内存中存放的数据具有值和类型。
变量只是单纯指向对象的引用,称之为对象引用。

python的***动态类型机制***会将变量名称a和对象123动态绑定,变量名称b和对象[1,2,3]动态绑定,然后,a会指向内存中的123,变量a成为对象123的对象引用,b会指向内存中的[1,2,3],b成为对象[1,2,3,4]的对象引用。
在这里插入图片描述

二.可变对象和不可变对象

可变对象:存在内存中的值可以变化,包括list, dict
不可变对象:存在内存中的值不可以变化, 包括 int, string, float. tuple

# 可变对象
a = 123
print(id(a)) #查看a指向的对象地址,为14452176928
a += 2
print(id(a)) #查看a指向的对象地址,变化为4452176992

# 不可变对象
b = [1,2,3]
print(id(b)) #查看b指向的对象地址,为140515147088392
b += [4]
print(id(b)) #查看b指向的对象地址,仍然为140515147088392

代码中,变量名称a最初指向不可变对象123,当a被重新赋值,因为int类型是不可变的类型,所以a会指向新的对象1234,原来的对象123会因为python的***垃圾回收机制***销毁。
变量名称b最初指向可变对象[1,2,3], 当b添加新的元素4时候,即指向的可变对象添加新的元素4,对象由[1, 2, 3]变为[1, 2, 3, 4], 还是在原来的内存地址中。
在这里插入图片描述

三.赋值/浅拷贝/深拷贝

不可变对象的赋值/浅拷贝/深拷贝较为简单,三者具有相同的效果
可变对象的赋值/浅拷贝/深拷贝较为复杂

不可变对象的赋值/浅拷贝/深拷贝

a = 123
b = a # 赋值
# b = copy.copy(a) #浅拷贝
# b = copy.deepcopy(a)# 深拷贝
print(id(a))
print(id(b)) # a和b的地址一样

b += 2 
print(a) # a=123
print(b) # b=125
print(id(a)) # int类型是不可变对象,a指向的对象不变:值和地址保持不变
print(id(b)) # b指向了新的对象,地址发生变化,此时a和b的地址不同

在这里插入图片描述
不可变对象的赋值/浅拷贝/深拷贝是一样的效果

可变对象的赋值

a = [1, 2, 3]
b = a

print(id(a))
print(id(b)) # a和b的地址一样

b += [4] 
print(a) # a=[1,2,3,4]
print(b) # b=[1,2,3,4]
print(id(a)) # list是可变对象,a指向的对象的地址不变,但值变化
print(id(b)) # b仍然指向该list对象,该对象的地址不变,但值变化,a和b的地址一样

在这里插入图片描述

可变对象的浅拷贝

import copy

a = [1, 2, 3]
b = copy.copy(a) # b指向新对象,和a指向的对象有相同的值,仅地址不同
# b = copy.deepcopy(a) # 深拷贝
print(id(a)) # 140515143437448
print(id(b)) # 140515147090312, 此时a和b指向不同的对象

b += [4]
print(a) # a=[1, 2, 3]
print(b) # b=[1, 2, 3,4]

print(id(a)) # a仍然指向对象[1, 2, 3]
print(id(b)) # b指向的对象地址也未变化,但是值变为[1, 2, 3, 4], 此时a和b地址仍然不同

在这里插入图片描述
上面的情况,可变对象的浅拷贝与深拷贝是相同的效果

复杂的可变对象的浅拷贝

import copy

c = [7, 8, 9]
a = [1, 2, 3, [c]]
b = copy.copy(a) # b指向新对象,和a指向的对象有相同的值,仅地址不同,但是a和b中指向的子对象是同一个对象,即相同的地址和值
print(id(a)) # 140515143437448
print(id(b)) # 140515147090312, 此时a和b指向不同的对象

b += [4]
print(a) # a=[1, 2, 3, [7, 8, 9]]
print(b) # b=[1, 2, 3, [7, 8, 9], 4]
print(id(a)) # a仍然指向原始对象,值和地址没有变化
print(id(b)) # b指向的对象地址发生变化,值也变化

c+=[10]
print(a) # a=[1, 2, 3, [7, 8, 9, 10]]
print(b) # b=[1, 2, 3, [7, 8, 9, 10], 4]
print(id(a)) # a仍然指向原始对象,地址没有变化,值发生变化
print(id(b)) # b指向的对象地址发生变化,值发生变化

当可变对象中嵌套可变对象时,浅拷贝,a和b指向的嵌套可变对象仍然是同一个对像
在这里插入图片描述

复杂的可变对象的深拷贝

import copy

c = [7, 8, 9]
a = [1, 2, 3, [c]]
b = copy.deepcopy(a) # b指向新对象,和a指向的对象有相同的值,仅地址不同,同时a和b指向的子对象也不再是同一个对象
print(id(a)) # 140515143437448
print(id(b)) # 140515147090312, 此时a和b指向不同的对象

b += [4]
print(a) # a=[1, 2, 3, [7, 8, 9]]
print(b) # b=[1, 2, 3, [7, 8, 9], 4]
print(id(a)) # a仍然指向原始对象,值和地址没有变化
print(id(b)) # b指向的对象地址发生变化,值也变化

c+=[10]
print(a) # a=[1, 2, 3, [7, 8, 9, 10]]
print(b) # b=[1, 2, 3, [7, 8, 9], 4]
print(id(a)) # a仍然指向原始对象,地址没有变化,值发生变化
print(id(b)) # b指向的对象地址没有发生变化,值也没有发生变化

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python 赋值/浅拷贝/深拷贝的区别 的相关文章

随机推荐