使用python 3取消python 2对象

NDe*_*vox 114 python pickle python-2.4 python-2to3 python-3.x

我想知道是否有任何方法可以加载Python 2.4中使用Python 3.4进行pickle的对象.

我已经在大量公司遗留代码上运行2to3以使其保持最新状态.

完成此操作后,运行该文件时出现以下错误:

  File "H:\fixers - 3.4\addressfixer - 3.4\trunk\lib\address\address_generic.py"
, line 382, in read_ref_files
    d = pickle.load(open(mshelffile, 'rb'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1: ordinal
not in range(128)
Run Code Online (Sandbox Code Playgroud)

寻找在争用酸洗对象,这是一个dict在一个dict,包含类型的键和值str.

所以我的问题是:有没有办法加载一个对象,最初在python 2.4中使用python 3.4进行腌制?

Mar*_*ers 171

您必须告诉pickle.load()如何将Python字节串数据转换为Python 3字符串,或者您可以pickle将它们保留为字节.

默认设置是尝试将所有字符串数据解码为ASCII,并且解码失败.查看pickle.load()文档:

可选的关键字参数是fix_imports,encodingerrors,用于控制Python 2生成的pickle流的兼容性支持.如果fix_imports为true,则pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称.编码错误告诉pickle如何解码Python 2腌制的8位字符串实例; 这些默认分别为'ASCII'和'strict'.该编码可以是"字节"作为字节对象读取这些8位串的实例.

设置编码latin1可以直接导入数据:

with open(mshelffile, 'rb') as f:
    d = pickle.load(f, encoding='latin1') 
Run Code Online (Sandbox Code Playgroud)

但是您需要验证没有使用错误的编解码器解码您的字符串; Latin-1适用于任何输入,因为它直接将字节值0-255映射到前256个Unicode码点.

另一种方法是使用加载数据encoding='bytes',然后解码所有bytes键和值.

请注意,在3.6.8,3.7.2和3.8.0之前的Python版本中,除非您使用,否则将破坏Python 2 datetime对象数据的取消encoding='bytes'.

  • @EpicAdv:你可以创建一个pickle_options字典,它对于python 2是空的,或者是''encoding':'latin1'`并发送\*\*pickle_options来pickle.这样它应该在两个版本中运行. (10认同)
  • @EpicAdv:您不需要使此代码与Python 2兼容; 这个问题是关于如何将Python 2 pickle加载到Python 3中.为Python 2完全删除`encoding`关键字. (2认同)
  • 我意识到 `datetime` 注释不是这个答案的主要内容,但对于未来的读者,我想指出即使是 Python 3 的“固定”版本仍然需要 `encoding='latin-1'`解开 Python 2 日期时间。如果您腌制的 Python 2 数据碰巧包含以非 Latin-1 编码的日期时间和字节串,那么您毕竟还是使用 `encoding='bytes'` 更好。 (2认同)

Sre*_*A R 12

当您的对象包含numpy数组时,使用encoding ='latin1'会导致一些问题.

使用encoding = bytes会更好.

有关使用encoding = bytes的完整说明,请参阅此答案

  • @sreeragh-ar:您能举例说明您遇到的问题吗?我有一个二维的“numpy.ndarray”(numpy 1.14),在Python 2.7中使用“cPickle.dumps()”腌制,并在Python 3中使用“pickle.loads(...,encoding='latin1')”取消腌制工作正常。 (2认同)