在Python中复制字典的快速方法


92

我有一个Python程序,可与字典配合使用。我必须复制字典数千次。我需要密钥和关联内容的副本。该副本将被编辑,并且不得链接到原始副本(例如,副本中的更改不得影响原始副本。)

键是字符串,值是整数(0/1)。

我目前使用一种简单的方法:

newDict = oldDict.copy()

对我的代码进行性能分析表明,复制操作花费了大部分时间。

有没有更快的替代dict.copy()方法?什么是最快的?


1
如果该值可以是0或1,那么boolint
萨米尔·塔尔瓦尔

5
如果您需要它们的数千份副本,位掩码会更好吗?
Wooble

@Samir不在boolPython中命名int
圣诞老人

不过,我同意,位掩码可能对您更有效(实际上取决于您如何使用此“ dict”)。
圣诞老人

1
需要说明的是,该bool类型实际上是该类型的子类(subtype?)int
圣诞老人

Answers:


64

查看Python 操作的C源代码dict,您会发现它们做的非常幼稚(但有效)。从本质上讲,它可以归结为PyDict_Merge

PyDict_Merge(PyObject *a, PyObject *b, int override)

这样可以快速检查诸如它们是否是同一对象以及它们中是否包含对象。之后,它会对目标dict进行大量的一次大小调整/分配,然后将其一一复制。我看不到您的速度比内置速度快得多copy()


1
听起来我最好重写代码以完全避免使用字典-或使用可以完成相同工作的更快的数据结构。非常感谢您的回答!
Joern

56

如您所说,表面上dict.copy更快。

[utdmr@utdmr-arch ~]$ python -m timeit -s "d={1:1, 2:2, 3:3}" "new = d.copy()"
1000000 loops, best of 3: 0.238 usec per loop
[utdmr@utdmr-arch ~]$ python -m timeit -s "d={1:1, 2:2, 3:3}" "new = dict(d)"
1000000 loops, best of 3: 0.621 usec per loop
[utdmr@utdmr-arch ~]$ python -m timeit -s "from copy import copy; d={1:1, 2:2, 3:3}" "new = copy(d)"
1000000 loops, best of 3: 1.58 usec per loop

感谢您的比较!将尝试重写代码,以避免在大多数地方使用dict复制。再次感谢!
Joern

4
顺便做最后的比较,不计做进口每次都是与成本timeit-s说法:python -m timeit -s "from copy import copy" "new = copy({1:1, 2:2, 3:3})"。当你在它,拉出字典创建以及(对于所有的例子。)
托马斯·沃特斯

也许多次重复该过程会更好,因为一个特定镜头可能会有一些波动。
xiaohan2012 2014年

2
Timeit做到这一点;如它所说,它循环1000000次并取平均值。
utdemir 2014年

我的时间矛盾。a = {b:b在范围(10000)中的b}在[5]:%timeit copy(a)10000个循环中,最好为3:每个循环186 µs在[6]:%timeit deepcopy(a)100循环中,最佳3:每个循环14.1毫秒在[7]中:%timeit a.copy()1000个循环,最佳3:每个循环180微秒
Davoud Taghawi-Nejad

12

您能否提供一个代码示例,以便我可以看到您如何使用copy()以及在什么情况下使用?

你可以用

new = dict(old)

但是我不认为会更快。


5

我意识到这是一个旧线程,但这对于“ dict copy python”的搜索引擎来说是一个很高的结果,而“ dict copy performance”的搜索结果则是最高的,我认为这是相关的。

从Python 3.7开始,newDict = oldDict.copy()速度比以前快了5.5倍。值得注意的是,目前newDict = dict(oldDict)看来,这种性能并未提高。

有一点点的更多信息这里


3

根据您要猜测的内容,您可能需要包装原始词典并进行某种写时复制。

然后,“副本”是一个字典,如果它不包含键---而是本身进行了修改,则它会在“父”字典中查找内容。

这假定您不会修改原始文件,并且额外的查找最终不会花费更多。


2

测量取决于字典的大小。对于10000个条目,copy(d)和d.copy()几乎相同。

a = {b: b for b in range(10000)} 
In [5]: %timeit copy(a)
10000 loops, best of 3: 186 µs per loop
In [6]: %timeit deepcopy(a)
100 loops, best of 3: 14.1 ms per loop
In [7]: %timeit a.copy()
1000 loops, best of 3: 180 µs per loop
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.