需求:
1、复制原列表并产生一个新的列表
2、针对修改操作,使原列表和新列表独立开,修改其中的一个列表,另一个列表不变
# 原列表
list1 = ['tom', 'alex', ['albert', 'abel', 'adam']]
# 通过打印id,表示列表在内存中的地址
print(id(list1[0]), id(list1[1]), id(list1[2]))
print(id(list1[2][0]), id(list1[2][1]), id(list1[2][2]))
原列表在内存中的存储方式为:
在通常情况下,复制一个列表会使用:list2 = list1
,这只是赋值操作,在栈区里新创建list2
变量,将list1
的内存地址赋值给list2
。虽然可以实现需求1,对列表的读操作没有影响;但是对于需求2,如果对list1
的值做出修改,因为list2
的id与list1
的id相同,在遍历list2
值的时候,读取的是list1
的内存,结果将会是list1
修改后的值,也就是说,对于改操作,两个列表并没有独立开。
浅 Copy
为了实现上述需求,可以调用copy()
方法。
list1 = ['tom', 'alex', ['albert', 'abel', 'adam']]
list3 = list1.copy()
而后,通过打印每个列表id
探究原列表和新列表在内存中的存储方式。
print(id(list1), id(list3))
# 打印原列表各项的id
print(id(list1[0]), id(list1[1]), id(list1[2]))
print(id(list1[2][0]), id(list1[2][1]), id(list1[2][2]))
# 打印新列表各项的id
print(id(list3[0]), id(list3[1]), id(list3[2]))
print(id(list3[2][0]), id(list3[2][1]), id(list3[2][2]))
"""
打印结果:
id(list1):1898489782080;id(list3):1898489613760
# 原列表各项的id:
1898488642096 1898488642864 1898489783104
1898488332720 1898489830960 1898489831024
# 新列表各项的id:
1898488642096 1898488642864 1898489783104
1898488332720 1898489830960 1898489831024
"""
可以简单的画出存储形式:
通过打印的id
可以发现,在内存中新开辟了一个空间用来存储产生的新列表,但是从子列表的id
可以发现,并没有开辟新的内存空间用来存储子列表。此时,修改原列表某一项的值。
list1[0] = 'Tom'
list1[2][0] = 'Albert'
在内存中的变化如图所示:
在遍历两个列表各项的值时,明显可以发现,一级列表实现了改操作的独立,但由于没有开辟新的内存空间用以存储子列表,所以子列表的修改操作并没有独立开。
深 Copy
要想copy得到的新列表与原列表的改操作完全独立开,必须有一种可以区分可变类型和不可变类型的copy机制。这便是深Copy。
对于深Copy操作,必须要导入外部模块,再调用deepcopy()
方法
import copy
list1 = ['tom', 'alex', ['albert', 'abel', 'adam']]
list4 = copy.deepcopy(list1)
而后,通过打印每个列表id探究原列表和新列表在内存中的存储方式。
print(id(list1), id(list4))
# 打印原列表各项的id
print(id(list1[0]), id(list1[1]), id(list1[2]))
print(id(list1[2][0]), id(list1[2][1]), id(list1[2][2]))
# 打印新列表各项的id
print(id(list4[0]), id(list4[1]), id(list4[2]))
print(id(list4[2][0]), id(list4[2][1]), id(list4[2][2]))
"""
打印结果:
id(list1):2412909307776;id(list4):2412909305984
# 原列表各项的id:
2412908165680 2412908166448 2412909227456
2412907856368 2412909354800 2412909354864
# 新列表各项的id:
2412908165680 2412908166448 2412909308224
2412907856368 2412909354800 2412909354864
"""
可以简单的画出存储形式:
从存储形式中可以发现,在内存中新开辟了两块内存空间,用以存储复制产生的新列表,包括子列表。在此时,修改原列表某一项的值。
list1[0] = 'Tom'
list1[2][0] = 'Albert'
在内存中的变化为:
在遍历两个列表各项的值时,明显可以发现,list1
某项值的改变(包括子列表中某一项的值),不会引起深Copy产生的新列表。也就是说:对于原列表和新列表,针对改操作,两个列表已经完全独立开,完全实现了两个需求。
总结
- 对于浅Copy:如果原列表存储的都是不可变类型,浅copy完全可以实现需求。
- 对于深Copy:如果原列表存储有可变类型和不可变类型,深Copy才可以实现需求