用python 3解开python 2对象


129

我想知道是否有一种方法可以加载在Python 2.4和Python 3.4中腌制的对象。

我一直在大量公司遗留代码上运行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)

在争用中查看腌制的对象,它dict在中dict,包含键和type值str

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


1
Python 2.4是否具有该json模块?也许您可以编写一个2.4脚本来解污对象并将其保存为json对象,然后编写一个3.4脚本以读取json对象并将其另存为与3.4兼容的pickle对象。这将是对所有pickle文件运行的一次性操作。
凯文

我正在沿着类似的思路思考,考虑到这些是我认为可以将sys.stdout更改为文件并打印出来的命令,但是我想看看是否可以先加载它们
NDevox 2015年

有相关的问题特别是与日期时间做:stackoverflow.com/questions/24805105/...
约翰Ÿ

Answers:


189

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

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

可选的关键字参数是fix_importsencodingerrors,用于控制对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') 

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

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

请注意,直到使用3.6.8、3.7.2和3.8.0之前的Python版本,除非使用,否则对Python 2 datetime对象数据的解泄漏都是无效的encoding='bytes'


1
如何使其与Python 2向后兼容?显然,Python 2不存在编码参数
。– EpicAdv

2
@EpicAdv:您不需要使此代码与Python 2兼容;这个问题是关于如何2种泡菜加载的Python成Python 3.删除的encoding关键字完全用于Python 2.
马亭皮特斯

10
@EpicAdv:您可以创建一个pickle_options字典,该字典对于python 2来说是空的,或者具有,'encoding': 'latin1'然后将** pickle_options发送给pickle。这样,它就可以在两个版本中运行。
pipefish

@pipefish-聪明,但是您必须在某处检测正在使用的版本,因此您也可以根据版本不同而直接进行调用(一个带附加参数,一个不带额外参数)。但是至少您了解了EpicAdv的评论要点,而Martijn的评论根本没有解决。
约翰Y

2
我意识到datetime评论不是此答案的主要目的,但对于未来的读者,我想指出的是,即使是“固定”版本的Python 3仍然需要encoding='latin-1'释放Python 2的日期时间。如果您腌制的Python 2数据恰好同时包含日期时间和以Latin-1以外的其他方式编码的字节串,那么encoding='bytes'毕竟还是会更好。
约翰Y

15

encoding='latin1'当对象中包含numpy数组时,使用会引起一些问题。

使用encoding='bytes'会更好。

请参阅此答案以获取有关使用的完整说明encoding='bytes'


哪个问题?我应该注意什么?使用bytes将字符串转换为bytes(),因此,latin1如果可能的话,我更喜欢,但是我不清楚问题是什么。
Gulzar

2
@ sreeragh-ar:您能举一个遇到的问题的例子吗?我numpy.ndarray在Python 2.7中使用腌制了一个二维(numpy 1.14)cPickle.dumps(),并在Python 3中解腌pickle.loads(..., encoding='latin1')正常。
djvg

@djvg当我不得不将图像腌制为图像字符串并将其解开时,我遇到了问题。可以在这里找到代码。gist.github.com/sreeragh-ar/70205db3a43badbfa69f758faa898be3
Sreeragh AR

@Gulzar请参阅上面的要点以解决问题。拔除后图像损坏。
Sreeragh AR
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.