如何最好地创建Python字典的浅拷贝?

7

假设我们有一个简单的Python字典:

dict_ = {'foo': 1, 'bar': 2}

复制这个字典的更好方法是什么?

copy1 = dict(dict_)
copy2 = dict_.copy()

有没有一个强有力的理由支持一种方法胜过另一种方法?

+1:非常相关的问题,因为答案表明情况并不是完全清晰的! - Eric O. Lebigot
这下就没有所谓的“唯一正确的方法”了... - martineau
另一方面,你所说的“更好”是什么意思? - martineau
我所想的定义是“更合适、有利或明智”。 - davidchambers
6个回答

8
我通常使用dict构造函数:这使得你创建一个新的dict更加明显,而调用对象上的copy方法可能会复制任何东西。同样,对于list,我更喜欢通过调用构造函数来复制,而不是通过切片来复制。
请注意,如果你使用dict的子类,则使用copy方法可能会变得混乱:
>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> d['a']
0
>>> d.copy()
defaultdict(<class 'int'>, {'a': 0})
>>> dict(d)
{'a': 0}
>>> 
< p > defaultdictcopy 方法可以给你另一个 defaultdict ,但是除非你在子类中覆盖 copy 方法,否则默认操作就是给你一个 dict :< /p>
>>> class MyDict(dict): pass

>>> d = MyDict(a=1)
>>> d
{'a': 1}
>>> type(d)
<class '__main__.MyDict'>
>>> type(d.copy())
<class 'dict'>

这意味着您必须了解子类的内部细节才能知道copy方法将返回哪种类型。

3

有人可能更喜欢选项#1(dict(dict_)),因为它符合最小惊讶原则:您也可以对列表执行相同的操作:list(list_),而且列表没有copy()方法。

尽管如此,回答中提出了许多好观点。这表明可能没有明显更好的解决方案,只要您做您打算做的事情即可(例如,在某些代码中子类化dict可能是至关重要的)。因此,我建议根据回答中提出的要点选择适合您应用程序的选项!


1
这里有许多很好的答案,但为了未来读者的利益,我会选择这个作为最能表达缺乏共识的答案。 - davidchambers

3

实际上,这取决于你打算用它做什么。在库中,您可能需要改变某个类似字典的对象的副本,并且您需要一个相同对象的副本。其他API必须有一个实际的dict,因此会使用构造方法创建新的dict并使用该方法。但是,当您这样做时,会丢失实际的原始类型信息(和方法)。但总体而言,我更喜欢使用copy()方法,因为它清楚地说明它是类似于字典的对象的副本(不只是一个字典)。这使其更加灵活(鸭子类型)。


2
最好的方法是使用dict_.copy(),因为意图是自说明的。但是,使用dict形式可以创建具有额外键的副本:
d = dict(a, zoo=1, zar=2)

这与以下代码等效,但更短:

d = a.copy()
d.update(zoo=1, zar=2)

1
第二个更好,因为它明确地显示你正在复制。

2
第一个选项还明确显示您正在创建一个新字典...(虽然我不会投反对票 :)) - Eric O. Lebigot
好的,op 的意图是“复制”而不是创建一个新的字典 ;) - ismail
正如@Keith所指出的那样,它使用鸭子类型,并且正如@Duncan所指出的那样,可以通过子类化来使其工作,以便您获得派生类型的另一个实例。 - martineau
@Ismail:然而,一个包含旧字典内容的新字典就是一份副本。:) 双方都有很好的论点。这完全取决于一个人想要实现什么,特别是在继承方面。 - Eric O. Lebigot

0

我不喜欢 dict.copy() 方法:

  • 从名称上看不清楚 .copy() 做了什么样的复制
  • 子类必须重写它,否则它的语义将完全混乱
  • 浅拷贝可以用其他方式完成(如通用的 copy.copy()dict()

想象一个随机类,例如 Uber。- 你会如何尝试复制 u = Uber(...)

  1. dict(u)
  2. Uber(u)
  3. u.copy()
  4. copy.copy(u)

我认为第二种方案有最高的成功几率,或是失败的风险。- 这正是我想要的。


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