Given a pickle dump in python how to I determine the used protocol?

落花浮王杯 提交于 2021-01-26 11:04:32

问题


Assume that I have a pickle dump - either as a file or just as a string - how can I determine the protocol that was used to create the pickle dump automatically?

And if so, do I need to read the entire dump to figure out the protocol or can this be achieved in O(1)? By O(1) I think about some header information at the beginning of the pickle string or file whose read out does not require processing the whole dump.

Thanks a lot!

EDIT: I have an update on this, apparently the answer given below does not always work under python 3.4. If I simply pickle the value True with protocol 1, sometimes I can only recover protocol 0 :-/


回答1:


You could roll your own using picketools:

with open('your_pickle_file', 'rb') as fin:
    op, fst, snd = next(pickletools.genops(fin))
    proto = op.proto

It appears that a PROTO marker is only written as the first element where the protocol is 2 or greater. Otherwise, the first element is a marker or element that indicates if the protocol is 0 or 1.

Update into kludging even more land:

pops = pickletools.genops(pickle_source)
proto = 2 if next(pops)[0].proto == 2 else int(any(op.proto for op, fst, snd in pops))



回答2:


2020 update:

I tried the methods here (from @JonClements's answer and from the comments), but none seemed to give me the correct protocol.

The following works, however:

proto = None
op, fst, snd = next(pickletools.genops(data))
if op.name == 'PROTO':
    proto = fst

Alternative (not cool, as it unpickles the whole thing):

out = io.StringIO()
pickletools.dis(data, out)
firstline = out.getvalue().splitlines()[0]
if ' PROTO ' in firstline:
    proto = re.sub(r'.*\s+', '', firstline)
    proto = int(proto)

Application: I want to find out what pickle protocol has been used in a pandas.to_hdf() (if pickling has been used, which is not always the case) and, since I don't fancy analyzing the whole structure of the HDF5 file, I am using a MonkeyPatch to spy on what pickle.loads() is asked to deserialize.

Whoever lands here via a Google search, here is my whole (kludgy) setup:

__pickle_loads = pickle.loads


def mock_pickle_loads(data):
    global max_proto_found
    op, fst, snd = next(pickletools.genops(data))
    if op.name == 'PROTO':
        proto = fst
        max_proto_found = max(max_proto_found, proto)
    return __pickle_loads(data)


def max_pklproto_hdf(hdf_filename):
    global max_proto_found
    max_proto_found = -1
    with MonkeyPatch().context() as m:
        m.setattr(pickle, 'loads', mock_pickle_loads)
        try:
            pd.read_hdf(hdf_filename)
        except ValueError:
            pass
    return max_proto_found


来源:https://stackoverflow.com/questions/19807790/given-a-pickle-dump-in-python-how-to-i-determine-the-used-protocol

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!