Python 3によるPython 2オブジェクトのunpickle化


129

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)

競合しているpickle化されたオブジェクトを見ると、これはのdictでありdict、キーとtypeの値が含まれていますstr

だから私の質問は:もともとPython 2.4でピクルされたオブジェクトをPython 3.4でロードする方法はありますか?


1
Python 2.4にはjsonモジュールがありますか?おそらく、オブジェクトをunpickleしてjsonオブジェクトとして保存する2.4スクリプトを記述し、jsonオブジェクトを読み取って3.4互換のpickleオブジェクトとして保存する3.4スクリプトを記述できます。これは、すべてのpickleファイルに対して実行する1回限りの操作です。
ケビン

私はsys.stdoutをファイルに変更して印刷することができると考えているディクテーションであることを考慮して、同様の行に沿って考えていましたが、最初にそれらをロードできるかどうかを確認したい
NDevox

特に日付時刻に関係する必要が関連質問:stackoverflow.com/questions/24805105/...
ジョン・Y

回答:


189

あなたは指示する必要がありますpickle.load()PythonはPythonの3つの文字列にデータをバイト文字列に変換するために、またはあなたが言うことができるどのようにpickleバイトとしてそれらを残すこと。

デフォルトでは、すべての文字列データをASCIIとしてデコードしようとしますが、そのデコードは失敗します。pickle.load()ドキュメントを参照してください:

オプションのキーワード引数はfix_importsencoding、およびerrorsです。これらは、Python 2によって生成されたピクルストリームの互換性サポートを制御するために使用されます。エンコーディングエラーは、Python 2によってピクルされた8ビット文字列インスタンスをデコードする方法をpickleに指示します。これらのデフォルトは、それぞれ「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ではdatetime、を使用しない限り、Python 2 オブジェクトデータのunpickle化は失敗しますencoding='bytes'


1
これをPython 2と下位互換にする方法を教えてください。どうやら、Python 2にはエンコーディング引数が存在しないようです
EpicAdv 2017年

2
@EpicAdv:このコードをPython 2と互換性にする必要はありません。この質問は、Python 3ドロップに2つの漬物のPythonをロードする方法についてですencodingPythonの2のために完全にキーワード
マルタインピータース

10
@EpicAdv:Python 2では空であるか、持っているpickle_options辞書を作成して、'encoding': 'latin1'** pickle_optionsをpickleに送信できます。このように、両方のバージョンで実行する必要があります。
pipefish 2017

@pipefish-賢いですが、どこかで使用しているバージョンを検出する必要があるため、バージョンに応じて、呼び出しを別の方法で(単純に追加引数なしと追加なしで)より簡単に行うこともできます。しかし、少なくとも、EpicAdvのコメントの要点はわかりましたが、Martijnのコメントにはまったく対応していません。
John Y

2
私は実現するdatetimeコメントがこの回答の主な推進力はありませんでしたが、将来の読者のために、私は、Python 3のも、「固定」バージョンがまだ必要であることを指摘したいと思いencoding='latin-1'化したりunpickle化したりパイソン2日付時刻に。ピクルスにしたPython 2データに、datetimeとLatin-1以外でエンコードされたバイト文字列の両方が含まれている場合でもencoding='bytes'、結局のところ、使用した方がよいでしょう。
John Y

15

使い方は、encoding='latin1'あなたのオブジェクトは、それにnumpyの配列が含まれているいくつかの問題が発生します。

使用encoding='bytes'する方が良いでしょう。

使用の完全な説明については、この回答を参照してくださいencoding='bytes'


どの問題?何に注意すればいいですか?を使用bytesすると、文字列がbytes()に変換されるのでlatin1、可能であれば優先しますが、何が問題なのかはわかりません。
Gulzar

2
@ sreeragh-ar:発生した問題の例を挙げていただけますか?私はnumpy.ndarrayを使用してPython 2.7で2次元(numpy 1.14)にピクルスcPickle.dumps()化し、Python 3でunpickle を使用すると問題なくpickle.loads(..., encoding='latin1')動作します。
djvg

@djvg画像を画像文字列としてピクルス化し、ピックル解除する必要があるときに問題に直面しました。コードはここにあります。gist.github.com/sreeragh-ar/70205db3a43badbfa69f758faa898be3
Sreeragh AR

@Gulzar問題については、上記の要旨を参照してください。アンピクル処理後に画像が破損していました。
Sreeragh AR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.