如何高效地浅拷贝Python字典?

7 投票
6 回答
1074 浏览
提问于 2025-04-16 09:20

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

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

那么,复制这个字典的哪种方法更好呢?

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

有没有什么特别的理由让我们更倾向于某种方法而不是另一种呢?

6 个回答

3

这其实要看你具体想用它来做什么。在某些库里,你可能需要修改一个类似字典的对象的副本,而你希望这个副本和原来的对象是同一个。其他一些接口则必须使用真正的dict,所以会用构造方法创建一个新的dict来使用。但这样做的话,你就会失去原来对象的类型信息(和方法)。总体来说,我更喜欢使用copy()方法,因为它明确表示这是一个类似字典的对象的副本(而不仅仅是一个字典)。这样会更灵活(也就是鸭子类型)。

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}
>>> 

defaultdictcopy 方法会给你另一个 defaultdict,但是如果你没有在子类中重写 copy 方法,默认的行为就是给你一个 dict

>>> 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 的那一点,在某些代码中可能很重要)。所以,我建议你根据回答中提到的观点,选择最适合你应用的方案!

撰写回答