Let's suppose I have a "quite large" dictionary, where keys are objects with heavy __eq__ function
class MyObject():
def __eq__(self, other):
return <very heavy function call>
def __hash__(self):
return <not so heavy hash calculation>
mydict = {<MyObject>:<Int>}
The problem is that when I try to unpickle a pickled object, it requires much time. I believe that it is because pickle does not save the internal hash table, and when restoring it recalculates the dictionary.
I did a simple experiment:
import pickle
import pickletools
original = { 'a': 0, 'b': [1, 2, 3] }
pickled = pickle.dumps(original)
pickletools.dis(pickled)
results in:
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
There are no signs of a hashtree. It means that Pickle Machine has to recalculate hashtree after deserialization. But it is really dummy? Why pickle does not save the internal state of a dictionary and how one can struggle with it?