python 如何制作复杂列表的完全非共享副本?(深拷贝是不够的)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1601269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make a completely unshared copy of a complicated list? (Deep copy is not enough)
提问by Ashwin Nanjappa
Have a look at this Python code:
看看这个 Python 代码:
a = [1, 2, 3]
b = [4, 5, 6]
c = [[a, b], [b, a]] # [[[1, 2, 3], [4, 5, 6]], [[4, 5, 6], [1, 2, 3]]]
c[0][0].append(99) # [[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3, 99]]]
Notice how modifying one element of c
modifies that everywhere. That is, if 99
is appended to c[0][0]
, it is also appended to c[1][1]
. I am guessing this is because Python is cleverly referringto the same objectfor c[0][0]
and c[1][1]
. (That is their id()is the same.)
注意修改一个元素是如何c
在任何地方修改它的。也就是说,如果99
附加到c[0][0]
,它也附加到c[1][1]
。我猜这是因为 Python 巧妙地为and引用了同一个对象。(也就是说他们的id()是一样的。)c[0][0]
c[1][1]
Question:Is there something that can be done to c
so that its list elements can be safely locally modified? Above is just an example, my real problem has a list much more complicated, but having a similar problem.
问题:有什么可以做的,c
以便它的列表元素可以安全地在本地修改?以上只是一个例子,我真正的问题有一个更复杂的列表,但也有类似的问题。
(Sorry for the poorly formed question above. Python gurus please feel free to modify the question or tags to better express this query.)
(抱歉,上面的问题格式不正确。Python 专家请随时修改问题或标签以更好地表达此查询。)
回答by Alex Martelli
When you want a copy, you explicitly make a copy - the cryptical [:]
"slice it all" form is idiomatic, but my favorite is the much-more-readable approach of explicitly calling list
.
当你想要一个副本时,你明确地制作一个副本 - 神秘的[:]
“切片”形式是惯用的,但我最喜欢的是显式调用list
.
If c
is constructed in the wrong way (with references instead of shallow copies to lists you want to be able to modify independently) the best thing would be to fix the way it's built (why build it wrong and then labor to fix it?!), but if that's outside your control it IS possible to undo the damage -- just loop on c
(recursively if needed), with an index, reassigning the relevant sublists to their copies. For example, if you know for sure that c
's structure is two-level as you indicate, you can save yourself without recursion:
如果c
以错误的方式构建(使用引用而不是浅拷贝到您希望能够独立修改的列表),最好的办法是修复它的构建方式(为什么构建错误然后努力修复它?!) ,但如果这超出了您的控制范围,则可以消除损坏——只需循环c
(如果需要,递归),使用索引,将相关子列表重新分配给它们的副本。例如,如果您确定c
's 的结构如您所指的那样是两级的,那么您可以不用递归来拯救自己:
def fixthewronglymadelist(c):
for topsublist in c:
for i, L in enumerate(topsublist):
topsublist[i] = list(L)
Despite what other answers suggest, copy.deepcopy
would be hard to bend to this peculiar purpose, if all you're given is the wrongly made c
: doing just copy.deepcopy(c)
would carefully replicate whatever c's topology is, including multiple references to the same sublists! :-)
尽管其他答案暗示了什么copy.deepcopy
,但如果您给出的只是错误的c
做法,则很难屈服于这个特殊的目的:这样做copy.deepcopy(c)
只会仔细复制 c 的拓扑结构,包括对相同子列表的多次引用!:-)
回答by Brian
To convert an existing list of lists to one where nothing is shared, you could recursively copy the list.
要将现有的列表列表转换为不共享任何内容的列表,您可以递归复制该列表。
deepcopy
will not be sufficient, as it will copy the structure as-is, keeping internalreferences as references, not copies.
deepcopy
这还不够,因为它会按原样复制结构,将内部引用保留为引用,而不是副本。
def unshared_copy(inList):
if isinstance(inList, list):
return list( map(unshared_copy, inList) )
return inList
alist = unshared_copy(your_function_returning_lists())
Note that this assumes the data is returned as a list of lists (arbitrarily nested). If the containers are of different types (eg. numpy arrays, dicts, or user classes), you may need to alter this.
请注意,这假设数据作为列表列表(任意嵌套)返回。如果容器的类型不同(例如 numpy 数组、字典或用户类),您可能需要更改它。
回答by Stephan202
Use [:]
:
使用[:]
:
>>> a = [1, 2]
>>> b = a[:]
>>> b.append(9)
>>> a
[1, 2]
Alteratively, use copy
or deepcopy
:
copy
或者deepcopy
,使用或:
>>> import copy
>>> a = [1, 2]
>>> b = copy.copy(a)
>>> b.append(9)
>>> a
[1, 2]
copy
works on objects other than lists. For lists, it has the same effect as a[:]
. deepcopy
attempts to recursively copy nested elements, and is thus a more "thorough" operation that copy
.
copy
适用于列表以外的对象。对于列表,它与a[:]
. deepcopy
尝试递归复制嵌套元素,因此是一个更“彻底”的操作,copy
.
回答by Pesto
回答by Michael Dillon
To see Stephan's suggestion at work, compare the two outputs below:
要查看 Stephan 的工作建议,请比较以下两个输出:
a = [1, 2, 3]
b = [4, 5, 6]
c = [[a, b], [b, a]]
c[0][0].append(99)
print c
print "-------------------"
a = [1, 2, 3]
b = [4, 5, 6]
c = [[a[:], b[:]], [b[:], a[:]]]
c[0][0].append(99)
print c
The output is as follows:
输出如下:
[[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3, 99]]]
-------------------
[[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3]]]