【问题标题】:Deep copy vs. List Comprehension深拷贝与列表理解
【发布时间】:2021-01-17 06:33:13
【问题描述】:

我对编程比较陌生,而且我一直在理解一些东西,这似乎对于在 Python 中克隆对象非常基础。

假设我们有以下代码,但没有使用 deepcopy 模块:

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]

现在如果我们这样做:

copy[1] = [9999999]

然后它将返回以下内容:

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [[1, 2, 3], [9999999], [7, 8, 9]]

但是,如果我们只修改其中一个嵌套列表中的单个元素,例如:

copy[0][1] = 9999999

那么原始变量和复制变量都会返回相同的值:

nested_list = [[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]
copy = [[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]

为什么当我们给嵌套列表一个新值时它工作得很好,但是当我们给嵌套列表中的一个项目一个新值时,它也会改变原来的值?对变量 nested_listcopy 调用 id() 函数表明它们是独立的对象,至少在我的理解中是这样。

例如:

copy = nested_list                # copy and nested_list share the same id()
copy = [x for x in nested_list]   # now they have different id()
copy = deepcopy(nested_list)      # again they have different id()

我知道另一种解决方案是 deepcopy 功能,但是由于它非常慢,我想知道是否有其他解决方案?

提前感谢大家!

【问题讨论】:

  • 这不是python的一个有趣的功能吗...?我仍然有问题,甚至无法完全解释。
  • @goalie1998。不仅仅是蟒蛇。任何使用指针的语言,不管你怎么称呼它们。

标签: python logic python-module deep-copy


【解决方案1】:

copy = [x for x in nested_list] 发生的蜡黄副本正在创建一个新的副本对象,该对象具有不同的 id() 然后 nested_list 但其中的所有嵌套列表都具有与两个列表中的列表相同的 ID。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]
print(id(copy)) #54769064
print(id(nested_list)) #54546184
print([id(i) for i in copy]) #[58832096, 58831816, 58619384]
print([id(i) for i in nested_list]) #[58832096, 58831816, 58619384]

在进行深度复制copy = deepcopy(nested_list) 时,复制嵌套列表,同时创建具有新 id 的新列表,当为 copy[0][1] = 9999999 之类的嵌套列表之一分配新值时,只会更改复制的第一个列表项,而不是 @987654327 @值。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = deepcopy(nested_list)
copy[0][1] = 9999999
print(copy) #[[1, 9999999, 3], [4, 5, 6], [7, 8, 9]]
print(nested_list) #[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

【讨论】:

  • 非常感谢您的回答,现在我明白了!祝你有美好的一天
【解决方案2】:

copynested_list 的子列表在内存中的位置相同。并且所有对应的子列表相同的id。这就是你有这种行为的原因。

nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
copy = [x for x in nested_list]
print(id(copy[0]) == id(nested_list[0])) #True
print(id(copy) == id(nested_list)) #False

如果您知道要提前更改的sublists,则可以仅对该子列表进行深度复制,以加快性能。

【讨论】:

    【解决方案3】:

    我不知道您来自哪种编程语言,但变量引用在 python 中的工作方式不同。我建议您阅读这篇清楚地说明的文章。 https://www.python-course.eu/python3_deep_copy.php

    我还写了一篇关于变量引用的 Medium post。你可以去看看。

    基本上,当你有一个列表时会发生什么,然后做

    copy[1] = [9999999]
    

    实际上是在更改第一级引用。但是当你更深入地喜欢

    copy[0][1] = 9999999
    

    那么你在比你还没有复制的参考更深的层次上改变元素。把它想象成一棵树。复制功能就像浅复制,当您执行浅复制时,您只是复制并制作了第一个引用的另一个对象。但第 2 次、第 3 次以后保持不变。

    【讨论】:

    • 非常感谢您的解释,现在一切都清楚了。我也会检查你的文章。祝你有美好的一天
    猜你喜欢
    • 2014-05-25
    • 1970-01-01
    • 2011-02-09
    • 2019-01-22
    • 2022-01-15
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多