Does a slicing operation give me a deep or shallow copy?
官方的python文档说,使用切片操作符并在python中进行赋值,可以得到切片列表的一个很浅的副本。
但是当我写代码时,例如:
1 2 | o = [1, 2, 4, 5] p = o[:] |
当我写下:
1 2 | id(o) id(p) |
我得到了不同的ID,并且附加一个列表也不会反映在另一个列表中。它不是在创建一个深层次的副本,还是在某个地方我出错了?
您正在创建一个浅副本,因为嵌套值不会被复制,只会被引用。深度复制也将创建列表引用的值的副本。
演示:
1 2 3 4 5 6 7 8 9 10 | >>> lst = [{}] >>> lst_copy = lst[:] >>> lst_copy[0]['foo'] = 'bar' >>> lst_copy.append(42) >>> lst [{'foo': 'bar'}] >>> id(lst) == id(lst_copy) False >>> id(lst[0]) == id(lst_copy[0]) True |
这里嵌套字典不被复制;它只被两个列表引用。新元素
记住,Python中的所有内容都是一个对象,名称和列表元素只是对这些对象的引用。列表的副本创建一个新的外部列表,但新列表只接收对完全相同对象的引用。
适当的深度复制会递归地为列表中包含的每个对象创建新的副本:
1 2 3 4 | >>> from copy import deepcopy >>> lst_deepcopy = deepcopy(lst) >>> id(lst_deepcopy[0]) == id(lst[0]) False |
您应该知道,使用
考虑一个易于理解的内部字符串示例:
1 2 3 4 5 6 | >>> l1=['one'] >>> l2=['one'] >>> l1 is l2 False >>> l1[0] is l2[0] True |
现在对
1 2 3 4 5 | >>> l3=l1[:] >>> l3 is l1 False >>> l3[0] is l1[0] True |
现在复制
1 2 3 4 5 | >>> s1=l1[0][:] >>> s1 'one' >>> s1 is l1[0] is l2[0] is l3[0] True # they are all the same object |
尝试一个deepcopy,其中每个元素都应该被复制:
1 2 3 4 | >>> from copy import deepcopy >>> l4=deepcopy(l1) >>> l4[0] is l1[0] True |
在每种情况下,字符串
你可以强制一个不立即被拘留的例子:
1 2 3 4 5 | >>> s2=''.join(c for c in 'one') >>> s2==l1[0] True >>> s2 is l1[0] False |
然后可以使用python intern函数使该字符串引用缓存对象(如果找到):
1 2 3 4 5 | >>> l1[0] is s2 False >>> s2=intern(s2) >>> l1[0] is s2 True |
同样适用于不可变元组:
1 2 3 4 5 6 7 | >>> t1=('one','two') >>> t2=t1[:] >>> t1 is t2 True >>> t3=deepcopy(t1) >>> t3 is t2 is t1 True |
不可变列表(如整数)可以将列表成员相互关联:
1 2 3 4 5 6 7 8 | >>> li1=[1,2,3] >>> li2=deepcopy(li1) >>> li2 == li1 True >>> li2 is li1 False >>> li1[0] is li2[0] True |
因此,您可以使用您知道将要复制某些内容的python操作,但最终结果是对实习生不可变对象的另一个引用。