Python可变对象和不可变对象

1、可变对象和不可变对象

在python中,一切皆对象,对象必有的三个属性:地址、类型、值

1.1 可变对象与不可变对象

当对象的值发生变化,但内存地址没有改变时,则说明是可变类型
当对象的值发生变化,内存地址也发生改变时,则说明是不可变类型

不可变对象(值传递):

​ 内置类型的对象(int,float,bool,str,tuple,unicode)是不可变的。

可变对象(引用传递):

​ (list,set,dict)这样的内置类型的对象是可变的。

​ 自定义类通常是可变的。

可变对象作为函数参数时候,是赋值地址给函数参数,函数内对其修改时候,会影响到变量的变化,例如:

l = [1,2,3]
print(l) # [1, 2, 3]
class A():
def change(self,lst:list):
lst.append(9)
a = A()
a.change(l)
print(l) #[1, 2, 3, 9]

2、深拷贝和浅拷贝

赋值: 只是复制了新对象的引用,不会开辟新的内存空间。

浅拷贝: 创建新对象,其内容是原对象的引用

深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。

2.1 对于不可变对象的深浅拷贝

import copy
a=(1,2,3)
print("=====赋值=====")
b=a
print(a)
print(b)
print(id(a))
print(id(b))
print("=====浅拷贝=====")
b=copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))
print("=====深拷贝=====")
b=copy.deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))

结果:

=====赋值=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128
=====浅拷贝=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128
=====深拷贝=====
(1, 2, 3)
(1, 2, 3)
43481128
43481128

不可变对象类型,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。

一句话就是,不可变类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。

2.2 对于可变对象深浅拷贝

import copy
a=[1,2,3]
print("=====赋值=====")
b=a
print(a)
print(b)
print(id(a))
print(id(b))
print("=====浅拷贝=====")
b=copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))
print("=====深拷贝=====")
b=copy.deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))

结果:

=====赋值=====
[1, 2, 3]
[1, 2, 3]
37235144
37235144
=====浅拷贝=====
[1, 2, 3]
[1, 2, 3]
37235144
37191432
=====深拷贝=====
[1, 2, 3]
[1, 2, 3]
37235144
37210184

赋值: 值相等,地址相等

copy浅拷贝:值相等,地址不相等

deepcopy深拷贝:值相等,地址不相等

2.3 对于可变对象深浅拷贝(外层改变元素)

对于可变对象深浅拷贝(外层改变元素)

import copy
l=[1,2,3,[4, 5]]
l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l.append(6)
print(l)
print(l1)
print(l2)
print(l3)

结果:

[1, 2, 3, [4, 5], 6] #l添加一个元素6
[1, 2, 3, [4, 5], 6] #l1跟着添加一个元素6
[1, 2, 3, [4, 5]] #l2保持不变
[1, 2, 3, [4, 5]] #l3保持不变

对于嵌套可变对象,赋值操作只是复制了一份地址,改变会随着原变量l改变。浅拷贝只是拷贝了第一层的内容,但是嵌套的内层还是属于地址复制,所以浅拷贝能保证第一层即外层保持不变。

2.4 对于可变对象深浅拷贝(内层改变元素)

import copy
l=[1,2,3,[4, 5]]
l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l[3].append(6)
print(l)
print(l1)
print(l2)
print(l3)

结果:

[1, 2, 3, [4, 5, 6]] #l[3]添加一个元素6
[1, 2, 3, [4, 5, 6]] #l1跟着添加一个元素6
[1, 2, 3, [4, 5, 6]] #l2跟着添加一个元素6
[1, 2, 3, [4, 5]] #l3保持不变

1.外层添加元素时,浅拷贝不会随原列表变化而变化;内层添加元素时,浅拷贝才会变化。
2.无论原列表如何变化,深拷贝都保持不变。
3.赋值对象随着原列表一起变化。

posted @   饮一杯天上水  阅读(1464)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示