如何在 Python 3 中 pickle 和 unpickle 到可移植字符串

新手上路,请多包涵

我需要将一个 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 许可协议

阅读 584
2 个回答

pickle.dumps() 产生一个 bytes 对象。期望这些任意字节是有效的 UTF-8 文本(您通过尝试将其解码为 UTF-8 字符串所做的假设)是非常乐观的。如果它有效,那将是巧合!

一种解决方案是使用完全使用 ASCII 字符的旧 pickling 协议。这仍然是 bytes ,但由于这些字节仅包含 ASCII 代码点,因此可以毫无压力地将其转换为字符串:

 pickled = str(pickle.dumps(obj, 0))

您还可以使用其他一些编码方法将二进制腌制对象编码为文本,例如 base64:

 import codecs
pickled = codecs.encode(pickle.dumps(obj), "base64").decode()

解码将是:

 unpickled = pickle.loads(codecs.decode(pickled.encode(), "base64"))

pickle 与协议 0 一起使用似乎会产生比 base64 编码的二进制泡菜更短的字符串(并且 abarnert 的十六进制编码建议将比 base64 更大),但我没有严格测试它或任何事物。用你的数据测试它看看。

原文由 kindall 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果你想在环境中存储字节,而不是编码文本,这就是 environb 的用途。

这在 Windows 上不起作用。 (正如文档所暗示的那样,您应该检查 os.supports_bytes_environ 如果您使用的是 3.2+,而不是仅仅假设 Unix 有而 Windows 没有……)因此,您需要将字节走私到无论您的系统编码是什么,都可以编码的东西,例如,使用 backslash-escape ,甚至 hex 。所以,例如:

 if os.supports_bytes_environ:
    environb['pickled'] = pickled
else:
    environ['pickled'] = codecs.encode(pickled, 'hex')

原文由 abarnert 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题