【发布时间】:2020-05-06 15:42:39
【问题描述】:
假设我有一个“相当大”的字典,其中键是具有重 __eq__ 函数的对象
class MyObject():
def __eq__(self, other):
return <very heavy function call>
def __hash__(self):
return <not so heavy hash calculation>
mydict = {<MyObject>:<Int>}
问题是当我尝试解开腌制的物体时,它需要很多时间。我相信这是因为pickle没有保存内部哈希表,并且在恢复它时会重新计算字典。
我做了一个简单的实验:
import pickle
import pickletools
original = { 'a': 0, 'b': [1, 2, 3] }
pickled = pickle.dumps(original)
pickletools.dis(pickled)
结果:
0: \x80 PROTO 3
2: } EMPTY_DICT
3: q BINPUT 0
5: ( MARK
6: X BINUNICODE 'a'
12: q BINPUT 1
14: K BININT1 0
16: X BINUNICODE 'b'
22: q BINPUT 2
24: ] EMPTY_LIST
25: q BINPUT 3
27: ( MARK
28: K BININT1 1
30: K BININT1 2
32: K BININT1 3
34: e APPENDS (MARK at 27)
35: u SETITEMS (MARK at 5)
36: . STOP
highest protocol among opcodes = 2
没有哈希树的迹象。这意味着Pickle Machine 必须在反序列化后重新计算哈希树。但它真的是假的吗?为什么 pickle 不能保存字典的内部状态以及如何与之抗争?
【问题讨论】:
-
pickle 格式在 Python 实现中是标准化的——它们不能(仅)存储足以在一个解释器的一个版本中实现
dict的信息。跨度> -
需要另存为泡菜吗?如果您可以将其保存为 json 似乎更有效。
-
@Gust,它对我不起作用,因为加载后我需要一个 python
dict。如果我将使用json构建pythondictafterload 将需要相同的时间。如果是这样,我需要一种方法来使用预先计算的哈希值初始化 pythondict。 -
如果它实际上在加载过程中多次调用
__eq__,它也会在使用过程中多次调用__eq__,并且程序的其余部分也会很慢。在 unpickling 期间对__eq__的大量调用表明__hash__有问题。
标签: python serialization pickle