Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
给定python中的pickle转储,如何确定使用的协议?_Python_Pickle - Fatal编程技术网

给定python中的pickle转储,如何确定使用的协议?

给定python中的pickle转储,如何确定使用的协议?,python,pickle,Python,Pickle,假设我有一个pickle转储-无论是作为文件还是作为字符串-如何确定用于自动创建pickle转储的协议 如果是这样的话,我是否需要阅读整个转储以了解协议,或者这可以在O(1)中实现?根据O(1),我考虑pickle字符串或文件开头的一些头信息,其读取不需要处理整个转储 非常感谢 编辑:我对此有一个更新,显然下面给出的答案在Python3.4下并不总是有效。如果我用协议1简单地pickle值True,有时我只能恢复协议0:-/您可以使用picketools自己滚动: with open('your

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

如果是这样的话,我是否需要阅读整个转储以了解协议,或者这可以在O(1)中实现?根据O(1),我考虑pickle字符串或文件开头的一些头信息,其读取不需要处理整个转储

非常感谢


编辑:我对此有一个更新,显然下面给出的答案在Python3.4下并不总是有效。如果我用协议1简单地pickle值
True
,有时我只能恢复协议0:-/

您可以使用
picketools自己滚动:

with open('your_pickle_file', 'rb') as fin:
    op, fst, snd = next(pickletools.genops(fin))
    proto = op.proto
在协议为2或更大的情况下,PROTO标记似乎仅作为第一个元素写入。否则,第一个元素是一个标记或元素,指示协议是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))

2020年更新

我在这里尝试了这些方法(从@JonClements的答案和评论中),但似乎没有一个能给我正确的方案

然而,以下工作:

proto = None
op, fst, snd = next(pickletools.genops(data))
if op.name == 'PROTO':
    proto = fst
另一种选择(不酷,因为这会让整个事情变得不愉快):

应用程序:我想知道pandas.to_hdf()
(如果使用了pickle,情况并非总是如此)中使用了什么pickle协议,并且,由于我不喜欢分析HDF5文件的整个结构,我正在使用来监视要求反序列化的
pickle.loads()

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


这不会在
protocol=0
protocol=1
@alko之间定义,我想是的。。。你有没有具体的例子?是的,任何都可以
op,fst,snd=next(pickletools.genops(cPickle.dumps('123',protocol=0))
后跟
{MARK':0,'PROTO':fst}.get(op.name,1)
@smcatepillar我想这可能有点像兔子洞:)无论如何,如果PROTO是2的话,我确信2的PROTO是第一个。否则,如果proto为1(添加到答案中),您可以短路,而不是取最大值。这意味着只有proto 0需要完全扫描。如果做不到这一点,我就找不到任何简单的文档,所以可能需要破解
Pickle.load
函数。。。这给了我另一个想法…@SmCaterpillar有很多信息。。。而且,具有协议版本的pickle似乎只是协议2的一部分。所以,在该版本之前,检查它是否是协议0的唯一方法是确保它不是协议1。。。这就是这个答案的作用。。。(恶心)注意,没有完整性或有效性约束,除了取消勾选之外,您无法检查字符串是否为有效的pickle dump。这会产生一些后果:例如,缓冲区对象是可拾取的,但结果字符串是不可拾取的。
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)
__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