我需要将一个Python3对象pickle到一个字符串,我想从Travis CI构建中的环境变量中取消。问题是我似乎无法在Python3中找到一种方法来腌制可移植字符串(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'))
答案 0 :(得分:22)
pickle.dumps()
生成bytes
个对象。期望这些任意字节是有效的UTF-8文本(通过尝试将其解码为UTF-8中的字符串而做出的假设)非常乐观。如果有效的话就巧合了!
一种解决方案是使用完全使用ASCII字符的旧酸洗协议。这仍然是bytes
,但由于它只有ASCII,因此可以解压缩为没有压力的字符串:
pickled = pickled.dumps(obj, 0).decode()
您还可以使用其他编码方法将二进制pickle对象编码为文本,例如base64:
import codecs
pickled = codecs.encode(pickle.dumps(obj), "base64").decode()
解码将是:
unpickled = pickle.loads(codecs.decode(pickled.encode(), "base64"))
对协议0使用pickle
似乎导致比base64编码的二进制pickle更短的字符串(abarnert建议的十六进制编码将比base64更大),但我没有严格测试它什么的用你的数据测试它,然后看看。
答案 1 :(得分:1)
如果你想在环境中存储字节而不是编码文本,那就是environb
的用途。
这在Windows上不起作用。 (正如文档所暗示的那样,如果您使用的是3.2+,则应该检查os.supports_bytes_environ
,而不是仅仅假设Unix没有,而Windows则不会......)为此,您需要将字节走私到无论您的系统编码是什么,都可以编码,例如,使用backslash-escape
,甚至是hex
。所以,例如:
if os.supports_bytes_environ:
environb['pickled'] = pickled
else:
environ['pickled'] = codecs.encode(pickled, 'hex')
答案 2 :(得分:0)
我认为最简单的答案,特别是如果您不关心Windows,只是将字节存储在环境中,如my other answer中所述。
但是如果你想要一些干净和可调试的东西,你可能会更乐意使用设计为基于文本的格式。
pickle
确实有&#34;纯文本&#34;协议0,如kindall's answer中所述。它确实比协议3或4更具可读性,但它仍然不是我实际想要阅读的东西。
JSON更好,但它无法开箱即用datetime
。您可以为需要编码的少数类型提供自己的编码(stdlib&#39; s json
模块是可扩展的),或使用jsonpickle
之类的内容。对于您关心的每种类型,它通常更安全,更有效,更易读,而不是一般的&#34;包装图灵完整协议中的任意类型&#34;像pickle
或jsonpickle
这样的方案,但当然它还有更多的工作,特别是如果你有很多额外的类型。
JSON Schema允许您使用JSON定义语言,类似于您在XML中执行的操作。它带有内置的date-time
String format,而Python的jsonschema
库知道如何使用它。
YAML有一个标准扩展存储库,其中包含JSON不包含的许多类型,包括timestamp。大多数the zillion 'yaml' modules for Python已经知道如何对此类型的datetime
对象进行编码。如果您需要YAML所包含的其他类型,那么它的设计是可以声明性地扩展。如果您确实需要,那么库有相当于jsonpickle
的库,可以动态定义新类型。
最后,您总是可以编写XML语言。