【问题标题】:Possibility to use a python2 created shelve dictionary with python3 and support backward compatibility可以将 python2 创建的搁置字典与 python3 一起使用并支持向后兼容性
【发布时间】:2020-10-01 15:30:17
【问题描述】:

我使用 python2 创建了一个架子 python 字典,并希望使用 python3 访问它。还有一种方法可以保持它向后兼容,就像一旦你使用 python3 腌制了它,你可以返回并使用 python2 访问它

【问题讨论】:

    标签: python python-3.x python-2.7 dictionary


    【解决方案1】:

    查看pickle.dumppickle.dumps(和shelve.open)方法的protocol参数(fix_imports默认设置为True)。

    我将专注于pickle,因为shelve 得到pickle 的支持。

    这是使用协议 0(我的 CPython 2.7.17 的默认协议)腌制的对象的转储:

    >>> s = "(dp0\nS'a'\np1\n(lp2\nI0\naI1\naI2\naI3\naI4\nas."
    

    您可以使用 Python 3.6 加载它(协议 0 已处理,但您必须将字符串转换为字节):

    >>> import pickle
    >>> bs = s.encode("ascii")
    >>> obj = pickle.loads(bs)
    >>> obj == {'a': [0, 1, 2, 3, 4]}
    True
    

    但是如果你想使用 Python 3.6 的默认协议(协议 3)再次腌制它,你有:

    >>> pickle.dumps(obj)
    b'\x80\x03}q\x00X\x01\x00\x00\x00aq\x01]q\x02(K\x00K\x01K\x02K\x03K\x04es.'
    

    Python 2 将无法加载此转储! (ValueError: unsupported pickle protocol: 3)

    但是如果你指定一个 Python2 知道的协议,例如protocol = 2:

    >>> bs = pickle.dumps(obj, protocol=2)
    b'\x80\x02}q\x00X\x01\x00\x00\x00aq\x01]q\x02(K\x00K\x01K\x02K\x03K\x04es.'
    

    表示方式有点不同,但 Python 2 将能够加载此转储。


    总结一下:

    • 使用pickle.loads(s.encode("ascii")) 加载使用Python 2 转储的对象
    • 使用 pickle.dumps(obj, protocol=2).decode("ascii") 转储对象,使用 Python 2 处理的更高协议。

    我想坚持原来的协议,你可以使用pickletools模块找到协议,但这有点hacky:

    def get_protocol(dump):
        """
        :returns:   the protocol of the dump
        :raises:    ValueError if the byte are not a pickle dump.
        :raises:    StopIteration if the protocol was not found
        """
        import pickletools
        op, _, _ = next(pickletools.genops(dump))
        if op.proto < 2:
            return op.proto
        else:
            return next((arg for opcode, arg, _ in pickletools.genops(dump) if opcode.name == "PROTO"))
    
    >>> for p in range(5):
    ...     bs = pickle.dumps(obj, protocol=p)
    ...     print(get_protocol(bs), end='')
    01234
    

    现在,你可以这样做了:

    original_protocol = get_protocol(bs)
    obj = pickle.loads(bs)
    # do something with `obj`
    bs = pickle.dumps(obj, protocol=original_protocol)
    

    (这并不能保证表示完全一样。)

    【讨论】:

    • 感谢您的快速解决方案。我会尝试一下,但是是否可以将 shelve 转换为 json 并来回转换
    • @aadithyavenkat 请参阅stackoverflow.com/a/2259313/6914441 了解泡菜/搁置与 JSON。总结一下:pickle 是针对 Python 的,并且只针对 Python,而 JSON 可以被大多数常用语言处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 2015-07-17
    • 2014-07-18
    • 2019-02-10
    相关资源
    最近更新 更多