【发布时间】:2017-08-24 09:37:35
【问题描述】:
当我们需要从包含原始数据类型的字典中复制完整数据时(为简单起见,让我们忽略 datetime 等数据类型的存在),我们最明显的选择是使用 deepcopy,但 deepcopy 比实现相同目的的其他一些骇人听闻的方法,即使用序列化-反序列化,例如 json-dump-json-load 或 msgpack-pack-msgpack-unpack。效率上的差异可以在这里看到:
>>> import timeit
>>> setup = '''
... import msgpack
... import json
... from copy import deepcopy
... data = {'name':'John Doe','ranks':{'sports':13,'edu':34,'arts':45},'grade':5}
... '''
>>> print(timeit.timeit('deepcopy(data)', setup=setup))
12.0860249996
>>> print(timeit.timeit('json.loads(json.dumps(data))', setup=setup))
9.07182312012
>>> print(timeit.timeit('msgpack.unpackb(msgpack.packb(data))', setup=setup))
1.42743492126
json 和 msgpack(或 cPickle)方法比普通的 deepcopy 更快,这很明显,因为 deepcopy 在复制对象的所有属性方面也会做得更多。
问题:有没有一种更 Pythonic/内置的方式来实现字典或列表的数据副本,而不需要 deepcopy 的所有开销?
【问题讨论】:
-
在小数据集上衡量性能并据此得出结论很少有用。如果您有更多嵌套或更大的数据结构,
deepcopy仍然慢得多? -
@MSeifert 我同意您的反馈,但我的目的不是将 deepcopy 与任何方法进行比较,我的主要问题是如果我的兴趣只是数据副本,如何减少 deepcopy 的所有开销。
-
值得注意的是,
json的往返序列化并不总是等同于copy.deepcopy。例如,deepcopy将保留对同一对象的多个引用,如果它们嵌套在容器中。考虑D = {1: 2}; L = [D, D]。如果您使用deepcopy复制它,新列表仍将包含对单个 dict 的两个引用(D的副本)。使用json,您将获得两个独立的字典。使用json还会将字典中的整数键转换为字符串。我对msgpack不熟悉,所以不知道有没有和json一样的限制。
标签: python