我需要将一个 Python3 对象 pickle 为一个字符串,我想在 Travis CI 构建中从环境变量中解开它。问题是我似乎找不到在 Python3 中 pickle 到可移植字符串 (unicode) 的方法:
import os, pickle
from my_module import MyPickleableClass
obj = {'cls': MyPickleableClass, 'other_stuf': '(...)'}
pickled = pickle.dumps(obj)
# raises TypeError: str expected, not bytes
os.environ['pickled'] = pickled
# raises UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb (...)
os.environ['pickled'] = pickled.decode('utf-8')
pickle.loads(os.environ['pickled'])
有没有一种方法可以将 datetime.datetime
类的复杂对象序列化为 unicode 或 Python3 中的其他一些字符串表示形式,我可以将其传输到不同的机器并反序列化?
更新
我已经测试了@kindall 建议的解决方案,但是 pickle.dumps(obj, 0).decode()
引发了 UnicodeDecodeError
。尽管如此, base64 方法仍然有效,但它需要 额外的解码/编码 步骤。该解决方案适用于 Python2.x 和 Python3.x。
# encode returns bytes so it needs to be decoded to string
pickled = pickle.loads(codecs.decode(pickled.encode(), 'base64')).decode()
type(pickled) # <class 'str'>
unpickled = pickle.loads(codecs.decode(pickled.encode(), 'base64'))
原文由 Peter Hudec 发布,翻译遵循 CC BY-SA 4.0 许可协议
pickle.dumps()
产生一个bytes
对象。期望这些任意字节是有效的 UTF-8 文本(您通过尝试将其解码为 UTF-8 字符串所做的假设)是非常乐观的。如果它有效,那将是巧合!一种解决方案是使用完全使用 ASCII 字符的旧 pickling 协议。这仍然是
bytes
,但由于这些字节仅包含 ASCII 代码点,因此可以毫无压力地将其转换为字符串:您还可以使用其他一些编码方法将二进制腌制对象编码为文本,例如 base64:
解码将是:
将
pickle
与协议 0 一起使用似乎会产生比 base64 编码的二进制泡菜更短的字符串(并且 abarnert 的十六进制编码建议将比 base64 更大),但我没有严格测试它或任何事物。用你的数据测试它看看。