7

假设我有一个 pickle 转储 - 作为文件或字符串 - 我如何确定用于自动创建 pickle 转储的协议?

如果是这样,我是否需要阅读整个转储以找出协议,或者这可以在 O(1) 中实现吗?通过 O(1),我考虑了 pickle 字符串或文件开头的一些标题信息,其读出不需要处理整个转储。

非常感谢!

编辑:我对此有更新,显然下面给出的答案在 python 3.4 下并不总是有效。如果我只是用协议 1 腌制值True,有时我只能恢复协议 0 :-/

4

2 回答 2

5

您可以自己使用picketools

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

似乎 PROTO 标记仅作为协议为 2 或更大的第一个元素写入。否则,第一个元素是指示协议是 0 还是 1 的标记或元素。

更新到组合更多的土地:

pops = pickletools.genops(pickle_source)
proto = 2 if next(pops)[0].proto == 2 else int(any(op.proto for op, fst, snd in pops))
于 2013-11-06T09:48:13.543 回答
4

2020年更新

我在这里尝试了这些方法(来自@JonClements 的回答和评论),但似乎没有一个能给我正确的协议。

但是,以下工作:

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

替代方案(不酷,因为它解开了整个事情):

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)

应用程序:我想找出在 a 中使用了哪些 pickle 协议pandas.to_hdf()(如果使用了 pickle,情况并非总是如此),并且由于我不喜欢分析 HDF5 文件的整个结构,所以我正在使用MonkeyPatch监视pickle.loads()被要求反序列化的内容。

谁通过谷歌搜索登陆这里,这是我的整个(kludgy)设置:

__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
于 2020-12-05T00:31:38.413 回答