如何制作复杂列表的完全非共享副本?(深拷贝是不够的)

2022-01-20 00:00:00 python 复制 list

问题描述

看看这个 Python 代码:

Have a look at this Python code:

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]]]

注意修改 c 的一个元素是如何在任何地方修改它的.也就是说,如果 99 附加到 c[0][0],它也附加到 c[1][1].我猜这是因为 Python 巧妙地引用 相同的对象 用于 c[0][0]c[1][1].(就是他们的id()是一样的.)

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 referring to the same object for c[0][0] and c[1][1]. (That is their id() is the same.)

问题:是否可以对 c 进行一些操作,以便可以在本地安全地修改其列表元素?上面只是一个例子,我真正的问题有一个更复杂的列表,但有一个类似的问题.

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.

(抱歉,上面的问题格式不正确.Python 大师请随时修改问题或标签以更好地表达此查询.)

(Sorry for the poorly formed question above. Python gurus please feel free to modify the question or tags to better express this query.)


解决方案

要将现有的列表列表转换为不共享任何内容的列表,您可以递归地复制该列表.

To convert an existing list of lists to one where nothing is shared, you could recursively copy the list.

deepcopy 是不够的,因为它将按原样复制结构,将 internal 引用保留为引用,而不是副本.

deepcopy will not be sufficient, as it will copy the structure as-is, keeping internal references as references, not copies.

def unshared_copy(inList):
    if isinstance(inList, list):
        return list( map(unshared_copy, inList) )
    return inList

alist = unshared_copy(your_function_returning_lists())

请注意,这假定数据以列表列表的形式返回(任意嵌套).如果容器是不同类型的(例如 numpy 数组、字典或用户类),您可能需要更改它.

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.

相关文章