如果切片和list()都不创建列表副本,我如何获取列表的真正副本?

10 投票
2 回答
1914 浏览
提问于 2025-04-15 12:01

我正在尝试修改一个列表,因为我的修改有点复杂,而且列表也很大,所以我用下面的代码取了一个列表的切片。

tempList=origList[0:10]
for item in tempList:
    item[-1].insert(0 , item[1])
    del item[1]

我这样做是想着所有对列表的修改只会影响到tempList这个对象,而不会影响到origList这个对象。

但是当我把代码调试好并在原始列表上运行时,发现前十个项目(索引从0到9)被我在测试代码时的操作影响了。

于是我上网查了一下,发现有些资料说取切片会复制列表并创建一个新的列表。我还找到了一些代码,帮助我查看项目的ID,所以我从头创建了origList,并获取了前十个项目的ID。然后我又切片了一次,发现切片中的ID和origList前十个项目的ID是一样的。

我还发现更多的资料建议用一种更“Python风”的方式来复制列表,那就是:

tempList=list(origList([0:10])

我试了这个方法,结果发现tempList的ID还是和origList的ID匹配。

请不要建议更好的编码方式——我想在理解复制是怎么回事后,自己研究如何用列表推导式来实现。

根据Kai的回答,正确的方法是:

import copy
tempList=copy.deepcopy(origList[0:10])
id(origList[0])
>>>>42980096
id(tempList[0])
>>>>42714136

效果很好。

2 个回答

4

如果你复制一个对象,它里面的内容并不会被复制。在大多数情况下,这样的行为是你想要的。不过在你的情况下,你需要自己确保内容被复制。你可以使用 `copy.deepcopy`,但如果你有一个包含列表的列表,或者类似的结构,我建议使用 copy = [l[:] for l in list_of_lists],这样会快很多。

关于你的代码风格,有几点小建议:

  • `del` 是一个语句,不是一个函数,所以最好不要加括号,这样会让人困惑。
  • 在运算符和逗号后面加空格,会让你的代码更容易阅读。
  • 使用 `list(alist)` 可以复制一个列表,但比起 `alist[:]` 来说,它并没有更符合 Python 的风格。我觉得 `alist[:]` 更常用一些。
24

切片操作会创建一个浅拷贝。在你的例子中,我看到你在对item[-1]调用insert(),这意味着item是一个包含列表的列表。这就意味着你的浅拷贝仍然指向原来的对象。你可以把它想象成只是复制了指针,而不是实际的对象。

解决这个问题的方法是使用深拷贝。Python提供了一个copy模块来处理这种情况。当你搜索浅拷贝和深拷贝时,你会发现更多相关的信息。

撰写回答