如何高效地浅拷贝Python字典?
假设我们有一个简单的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}
>>>
defaultdict
的 copy
方法会给你另一个 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
的那一点,在某些代码中可能很重要)。所以,我建议你根据回答中提到的观点,选择最适合你应用的方案!