看看这个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]]]

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

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

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

有帮助吗?

解决方案

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

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

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

alist = unshared_copy(your_function_returning_lists())

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

其他提示

当您需要副本时,您明确地制作副本 - 密码 [:] " slice it all"形式是惯用的,但我最喜欢的是显式调用 list 的更易读的方法。

如果 c 以错误的方式构造(使用引用而不是浅层副本到列表,你希望能够独立修改),最好的方法是修复它的构建方式(为什么要构建)它是错误的,然后努力解决它?!),但如果这超出了你的控制范围,那么就可以撤消损害 - 只需循环 c (递归,如果需要),带索引,重新分配相关的副本列表。例如,如果你确定 c 的结构是你所指出的两级结构,你就可以自行保存而不会递归:

def fixthewronglymadelist(c):
  for topsublist in c:
    for i, L in enumerate(topsublist):
      topsublist[i] = list(L)

尽管有其他答案的建议, copy.deepcopy 很难屈服于这个特殊的目的,如果给你的是错误的 c :只做 copy.deepcopy(c)会仔细复制c的拓扑结构,包括对同一个子列表的多个引用! : - )

根据您的具体情况,您可能希望违反深层复制列表。

使用 [:]

>>> a = [1, 2]
>>> b = a[:]
>>> b.append(9)
>>> a
[1, 2]

另外,使用 copy deepcopy

>>> import copy
>>> a = [1, 2]
>>> b = copy.copy(a)
>>> b.append(9)
>>> a
[1, 2]

copy 适用于列表以外的对象。对于列表,它与 a [:] 具有相同的效果。 deepcopy 尝试递归地复制嵌套元素,因此更加“彻底”。 copy 的操作。

要查看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

输出如下:

[[[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]]]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top