python之深浅拷贝
文章目录
-
- python之深浅拷贝
-
- 一、为什么要有深浅拷贝?
- 二、赋值操作
- 三、浅拷贝
- 四、深拷贝
- 五、深浅使用总结
一、为什么要有深浅拷贝?
- 当涉及到容器类型的修改操作时,想要保留原来的数据和修改后的数据,这个时候就需要深浅拷贝。
二、赋值操作
Copysource_list = ['aaaa', 1111, ['bbbb', 2222]]
new_list = source_list
print('-------------------------观察1---------------------------')
print(id(source_list), id(new_list))
source_list[0] = 'AAAA'
source_list[-1][-1] = 3333
print('-------------------------观察2---------------------------')
print(id(source_list), id(new_list))
print(id(source_list[0]), id(new_list[0]))
print(id(source_list[-1][-1]), id(new_list[-1][-1]))
"""
赋值操作列表与新列表都是指向同一内存地址,2个列表中,只要有一个人的列表中的索引所对应的值的内存地址改变,则都改变
"""
- **结论:**赋值操作是把源列表容器的内存地址完完整整的多绑定一份交给新列表。
三、浅拷贝
- **用法:**list.copy()
- 观察1:对源列表copy以后,产生的新列表内存地址发生了改变,不再是同一个列表。而新列表与源列表中的可变不可变类型的值在没修改之前都是指向同一个值。
- 观察2:对源列表中不可变类型的值进行修改以后,对于不可变类型的值,都是产生新值,让源列表的索引指向新的内存地址,并不会影响新列表。
- 观察3:对源列表中可变类型的值进行修改以后,对于可变类型,我们可以改变类型中包含的值,但这个可变容器本身内存地址不变。即新列表的索引仍然指向原来的内存地址,于是新列表也跟着受影响。
Copysource_list = ['egon', 'alex', [1, 2]]
new_list = source_list.copy()
print('-------------------------观察1---------------------------')
print(new_list)
print(id(source_list), id(new_list))
print(id(source_list[0]), id(source_list[1]), id(source_list[2]))
print(id(new_list[0]), id(new_list[1]), id(new_list[2]))
print('-------------------------观察2---------------------------')
source_list[0] = 'EGON'
source_list[1] = 'ALEX'
print(source_list)
print(id(source_list[0]), id(source_list[1]), id(source_list[2]))
print(id(new_list[0]), id(new_list[1]), id(new_list[2]))
print('-------------------------观察3---------------------------')
print(id(source_list[2]), id(source_list[2][0]), id(source_list[2][1]))
print(id(new_list[2]), id(new_list[2][0]), id(new_list[2][1]))
source_list[-1][0] = 111
source_list[-1][1] = 222
print(new_list)
print(source_list)
print(id(source_list[2]), id(source_list[2][0]), id(source_list[2][1]))
print(id(new_list[2]), id(new_list[2][0]), id(new_list[2][1]))
"""
1、对源列表copy以后,产生的新列表内存地址发生了改变,不再是同一个列表。而新列表与源列表中的可变不可变类型的值在没修改之前都是指向同一个值。
2、对源列表中不可变类型的值进行修改以后,对于不可变类型的值,都是产生新值,让源列表的索引指向新的内存地址,并不会影响新列表。
3、对源列表中可变类型的值进行修改以后,对于可变类型,我们可以改变类型中包含的值,但这个可变容器本身内存地址不变。即新列表的索引仍然指向原来的内存地址,于是新列表也跟着受影响。
"""
- **结论:**把源列表第一层的内存地址不加区分的完全copy给一份新列表。(这里区分指的是可变,不可变类型的区分)
四、深拷贝
- 深拷贝对容器类型中的每一层得数据加以区分,对可变不可变类型区分对待。
- 争对不可变类型,拷贝以后任然还是用原来值的内存地址(省空间),但是当值一改,这时会开辟新的内存空间产生新的值,并与之绑定,于此同时两者之间互不影响。
- 争对可变类型,拷贝以后会开辟新得容器地址,在这个新的容器地址中,再次区分可变不可变类型。如果是不可变类型任然用原来值得内存地址(省空间),但是当值一改,这时又会开辟新的内存空间产生新的值,并与之绑定。如果是可变类型则又会开辟新得容器地址,再次对容器中得可变不可变类型进行判断、区分,以此类推。
- **用法:**第一步:import copy 第二步:copy.deepcopy(list)
- 观察1:
Copyimport copy
source_list = ['egon', 'alex', [1, 2]]
new_list = copy.deepcopy(source_list)
print(new_list)
print(id(source_list), id(new_list))
print('------------查看容器第一层------------')
print(' 不可变 不可变 可变')
print(id(source_list[0]), id(source_list[1]), id(source_list[2]))
print(id(new_list[0]), id(new_list[1]), id(new_list[2]))
print('------------查看容器第二层------------')
print(id(source_list[2][0]), id(source_list[2][1]))
print(id(new_list[2][0]), id(new_list[2][1]))
source_list[0] = 'EOGN'
source_list[1] = 'ALEX'
source_list[2][0] = 111
source_list[2][1] = 222
print('------修改以后,修改源列表,新列表所有值不会一起受影响-------')
print(source_list)
print(new_list)
- **结论:**把两个列表完完整整独立开,并且只争对该操作而不是读操作。
五、深浅使用总结
- **使用浅copy:**如果你想对容器类型进行修改操作时,想保留原来的数据和修改后的数据,这时只有容器类型的第一层全是不可变类型,这个时候就用浅copy。
- **使用深copy:**如果你想对容器类型进行修改操作时,想保留原来的数据和修改后的数据,且你想让两个列表完完全全独立开,这个时候就用深copy。