【发布时间】:2020-10-01 15:30:17
【问题描述】:
我使用 python2 创建了一个架子 python 字典,并希望使用 python3 访问它。还有一种方法可以保持它向后兼容,就像一旦你使用 python3 腌制了它,你可以返回并使用 python2 访问它
【问题讨论】:
标签: python python-3.x python-2.7 dictionary
我使用 python2 创建了一个架子 python 字典,并希望使用 python3 访问它。还有一种方法可以保持它向后兼容,就像一旦你使用 python3 腌制了它,你可以返回并使用 python2 访问它
【问题讨论】:
标签: python python-3.x python-2.7 dictionary
查看pickle.dump、pickle.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)
(这并不能保证表示完全一样。)
【讨论】: