Copying nested lists in Python
我想复制一个二维列表,这样如果我修改一个列表,另一个列表就不会被修改。
对于一维列表,我只需执行以下操作:
现在如果我修改b,a就不会被修改。
但对于二维列表来说,这并不适用:
1 2
| a = [[1, 2],[3, 4]]
b = a[:] |
如果我修改b,a也会被修改。
我该怎么解决这个问题?
- 很多时候,当人们使用嵌套列表并需要以这种方式复制它们时,他们确实希望使用numpy。
- imho,这只是语言中的一个错误。在两种情况下不同的行为应该是相同的-对于解释语言来说是典型的。如果代码很大,很难调试
- @Serhiipoklonskyi不,这不是虫子。当您执行b = a[:]操作时,会创建一个新的列表b,因此,例如a.append([5, 6])不会修改b,因为它只会更改a。但是,行a[1][0] = 5将更改b,因为它更改了b所指的列表。
- @Artemisfowl不适合我(a[1][0]也不修改b)。即使这样,我也不明白这有什么关系。问题是:当您执行a = b.copy()操作时,a在内存中成为一个单独的位置:既不是引用,也不是指向b的指针,即它是一个独立变量。但是,如果您执行a = b.copy(),并且b是一个数组,则该操作不起作用。怎么可能有任何合理的解释呢?如果b是一个数组,a = b.copy()必须创建一个自变量。否则它就是一个bug。P.S.无意无礼,如果我错了请向我解释
- @我不确定我是否完全理解?
- @阿尔忒弥斯福尔,让我试试看。想象一下:a是一维数组。想象一下你做了b = a.copy()。发生什么事了?b是a的副本,但与之无关。如果你换了a,b就没有什么变化。它有自己的存储单元。现在假设a是二维数组。假设您执行"b=a.copy()"。b是a的副本,但是如果你现在保存a的话,b也会被更改!你不觉得这种不一致和错误的行为吗?
- @不管怎样,只要看看这个问题。很明显,在一种情况下生成结果"x"的命令在另一种情况下生成结果"y"。不知道,对此没有有效的解释。我的意思是,编码本身是很困难的,语言必须清晰一致,而不是更困难。
- @Serhiipoklonskyi我认为你觉得这个困惑的原因是你错过了理解python。python实际上没有"二维数组",它只是有列表,可以包含其他列表。我试着用一个例子来说明:你用a = [[1, 2], [3, 4]]来定义a。然后创建一个a的副本:b = a.copy。这是一个不同的列表,但它包含相同的"子列表",这意味着更改b,例如b.append([5, 6]),不会更改a,但是更改b中的列表,例如b[0].append(3),也会更改a的第一个列表。
- @阿耳特米斯福尔…因为子列表不是深度副本,只有主列表是?所以修改主列表不会改变它的副本,但是修改子列表会改变它?换句话说,为了解决这个问题,我可以做a = [i.copy() for i in b]我是否理解正确?
- @阿耳忒弥斯福尔是的,现在为我工作。好吧,那不是一个bug,只是缺乏理解。我真的认为,你的解释一定是这个问题的真实答案。谢谢你抽时间!
- @不客气。
对于更通用的解决方案,不管维度的数量如何,都可以使用copy.deepcopy():
1 2
| import copy
b = copy.deepcopy(a) |
- 虽然在大多数情况下,我可能会说from copy import deepcopy,因为名称冲突不太可能发生,而且看起来更好。;)
- @大卫,你说得对。我更喜欢导入模块以避免名称冲突,而不是逐个处理函数。:)
- 请注意,这也将对列表中的实际元素进行deepcopy。
- @dav,我不同意,通常最好使用module.function()格式。
- "名称空间是一个非常好的主意——让我们做更多的事情吧!"
- @福格勒伯德:个人喜好。
- @然而,pep-8实际上似乎暗示了from ... import ...是标准的,除非存在名称空间冲突:python.org/dev/peps/pep-0008(参见"导入")。
- 有关详细信息,请阅读effbot.org/zone/import-confusion.htm。
- 我看不到真正适用于这里的任何东西——大多数只是一个没有支持的意见陈述,然后提到潜在的循环或延迟导入问题,这些问题不适用于标准库,实际上也不适用于大多数模块。实际上,"循环进口问题"一节甚至明确指出,该问题不需要from .. import用法来体现。
- +1.视情况而定。我个人喜欢避免使用copy/deepcopy(在现实生活中很少有有效的用例;对于一个超过2维的IMO列表也是如此)
- 你能提供一个用例吗?我正试图复制一个二维列表,但我不确定用您提供的变量名替换什么。
- @johnlocke b是新名单,a是旧名单。x在内部使用。