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

Ash*_*ppa 6 python copy list

看看这个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]]]
Run Code Online (Sandbox Code Playgroud)

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

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

(对不起,上面提到的问题很糟糕.Python大师请随意修改问题或标签以更好地表达此查询.)

Ale*_*lli 8

当你想要一个副本时,你明确地制作一个副本 - [:]密码"切片全部"形式是惯用的,但我最喜欢的是显式调用的更易读的方法list.

如果c以错误的方式构造(使用引用而不是浅层副本到列表,您希望能够独立修改),最好的方法是修复它的构建方式(为什么构建错误然后用来修复它?!) ,但如果这超出了您的控制范围,则可以撤消损坏 - 只需循环c(如果需要,递归),使用索引,将相关子列表重新分配给其副本.例如,如果您确定c结构是指定的两级结构,则可以在不递归的情况下保存自己:

def fixthewronglymadelist(c):
  for topsublist in c:
    for i, L in enumerate(topsublist):
      topsublist[i] = list(L)
Run Code Online (Sandbox Code Playgroud)

尽管其他答案提出了什么copy.deepcopy,但如果给出的所有内容都是错误的,那就很难屈服于这个特殊的目的c:只是copy.deepcopy(c)谨慎地复制c的拓扑结构,包括对同一个子列表的多次引用!:-)


Bri*_*ian 8

要将现有列表列表转换为无共享列表,可以递归复制列表.

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

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

alist = unshared_copy(your_function_returning_lists())
Run Code Online (Sandbox Code Playgroud)

请注意,这假定数据作为列表列表(任意嵌套)返回.如果容器具有不同的类型(例如,numpy数组,dicts或用户类),则可能需要更改它.


Ste*_*202 5

用途[:]:

>>> a = [1, 2]
>>> b = a[:]
>>> b.append(9)
>>> a
[1, 2]
Run Code Online (Sandbox Code Playgroud)

改变,使用copydeepcopy:

>>> import copy
>>> a = [1, 2]
>>> b = copy.copy(a)
>>> b.append(9)
>>> a
[1, 2]
Run Code Online (Sandbox Code Playgroud)

copy适用于列表以外的对象.对于列表,它具有相同的效果a[:].deepcopy尝试以递归方式复制嵌套元素,因此是一种更"彻底"的操作copy.


Pes*_*sto 5

根据您的具体情况,您可能希望对此列表的深层副本起作用.