嵌套字典使用copy()还是deepcopy()?

10

我试图在代码开头存储一个字典模板,大部分函数将使用这个模板:

  • 字典:键 = 客户名称,值 = 字典2
  • 字典2:键 = 用户名称,值 = None

我用所有客户和他们的用户来填充它。然后代码的每个部分都可以复制这个字典并生成自己的输出。目标是每个输出都有相同的“基本”字典结构,就像一个模板,其中的None可以修改。

对于每个使用这个字典的过程,我使用以下内容:

process1dict = clientdict 
# processing 1
output1dict = ... #modified version of original clientdict, the None values have been replaced by dictionaries/lists

process2dict = clientdict
# processing 2
output2dict = ... #same here but could be different

我遇到的问题是,每次将 cliendict 复制到一个进程中,它都会发生变化!我注意到这是因为在我的初始 cliendict 中有 None 值,它会根据每个进程的输出而改变(当然取决于每个进程的输出)。

编辑:我找到了 copy 库,但是 copy() 似乎对我的情况没有帮助。我将尝试使用 deepcopy(),但为什么 copy() 不起作用?为什么会用 deepcopy() 起作用呢?


1
是的,你需要进行深拷贝 -> 如果没有这样做,clientdictDNT 只会指向相同的底层字典,所以当你修改 clientdict 时它也会被修改,你也可以使用 dict(clientdict)clientdict.copy() - TemporalWolf
1
你应该阅读SO老手Ned Batchelder的文章:关于Python名称和值的事实与神话 - PM 2Ring
如果不使用deepcopy(),那么新字典中的成员将指向嵌入在基本字典中的字典。deepcopy()会复制被复制字典中的内容。 - Rick
感谢您的文章和回答。如果我理解正确,当我使用嵌套字典作为可变对象时,如果我执行“copy()”并且在我的过程中使用一些“更改”函数,例如“.append()”,它将直接链接到值本身(特别是这里的“None”值)。如果我想像使用字典模板一样使用它(就像我在这里做的那样),我认为最好使用“deepcopy()”。我明天会试一试! - Alex
1个回答

18

当你使用可变集合(如字典或列表)进行操作并执行赋值时,默认情况下不会创建该对象的副本。例如,将某个字典b赋值给另一个字典a会创建从b到原始对象a的引用,因此当你更改b时,间接地也更改了a

看下面的基本示例:

>>> orig = {"a": 1, "b": 2}
>>> new = orig
>>> new["a"] = 9
>>> orig
{'a': 9, 'b': 2}
>>> new
{'a': 9, 'b': 2}
>>> new is orig
True
为了解决这个问题并保持neworig字典作为相互不引用的独立对象,当将orig赋值给new时,需要使用deepcopy
>>> import copy
>>> orig = {"a": 1, "b": 2}
>>> new = copy.deepcopy(orig)
>>> new["a"] = 9
>>> orig
{'a': 1, 'b': 2}
>>> new
{'a': 9, 'b': 2}
>>> new is orig
False

此外,这里有一个针对上述Python文档的tl;dr:

在Python中,赋值语句不会复制对象,它们只是在一个目标和一个对象之间创建了绑定关系。对于可变集合或包含可变项的集合,有时需要进行复制,以便可以更改一个副本而不影响另一个。


1
在许多情况下,深拷贝是不必要的,甚至可能会有害。如果您有一个属于两个客户端的对象User(“Somebody”),您可能不想将其拆分为两个等效对象并单独进行更改。如果您不需要或不想使用copy.deepcopy,则可以使用dict.copy代替。orig = {"a": 1, "b": 2}; new = orig.copy() - Adam Smith
1
在这种情况下,我没有属于两个客户的用户名对象。我现在遇到的问题是,这个“clientdict”字典被用作模板,并且“None”值被用作空白字符来填充进程中的其余字典。当我第一次尝试使用“copy()”时,也就是在编写问题的最后一分钟,我发现它没有起作用,现在我想我明白了为什么,感谢你们的评论!谢谢大家。 - Alex
1
#点赞。这很深刻且有帮助。 - niCk cAMel
1
你救了我的晚上伙计!谢谢 =) - ykatchou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接