15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pickle 2系で作ったものを3系で読み込むには

Last updated at Posted at 2015-10-30

#2系でpickle.dumpしたものを3系でpickle.loadしたい。
※文字の場合、byteのままなので、文字に直す方法を追記
※逆に、3系で作ったものを2系で読み込む方法を追記

いろいろ仕様が載ってるとこ:http://docs.python.jp/3.4/library/pickle.html

3系に移行して少し経って、前作ったpickleでdumpしたデータを読みたくなったが、エラーが出た。
#エラー

pickle-load-error.
# test_w_2.pklは、2系で[1]をdumpしたファイル
In [25]: fin = open('test_w_2.pkl', 'r') 
In [26]: pickle.load(fin)    
TypeError: a bytes-like object is required, not 'str'       

エラーがこのように出て、strではない?bytesにしないといけないっぽい
##解決方法
openの時のオプションに'rb'をつければいいっぽい(バイナリーモード)

piclkle-load.
In [38]: fin = open('test_wb_2.pkl', 'rb')
In [39]: pickle.load(fin)                                                                              
Out[39]: [1]   

##[追記]dumpしたのがstringの場合
上記の例では、[1]しかdumpしていませんでした。
リストの中に文字列を含んでいた場合にはloadできない場合があるようです。
pickle.loadする際に、encoding='bytes'でエンコード方法の変更。
受け取ったlistの中身のものを.decode('utf8')を用いてstringに変換する作業が必要です。

##python2.7.9

pickle.dump
>>> pickle.dump(['あいうえお'], open('test.pkl', 'w')  )

###python3.5.0

pickle.load
# 普通に読み込んでエラー
>>> pickle.load(open('test.pkl', 'r') )                                                                
Traceback (most recent call last):                                                                     
  File "<stdin>", line 1, in <module>                                                                  
TypeError: a bytes-like object is required, not 'str'                                                  

# バイナリーで読み込んでも'ascii'に対応してないのでエラー
>>> pickle.load(open('test.pkl', 'rb') )                                                               
Traceback (most recent call last):                                                                     
  File "<stdin>", line 1, in <module>                                                                  
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)      

#  エンコード方法を変えたら読み込めたが、bytesのままで読めない
>>> pickle.load(open('test.pkl', 'rb'), encoding='bytes' )                                             
 [b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a']                                      

# decode('utf8')を使い、リスト内の各要素をdecode
>>> list(map(lambda x: x.decode('utf8'), pickle.load(open('test.pkl', 'rb'), encoding='bytes' ) ) )    
 ['あいうえお']  

##[追記]逆に、3系で作ったものを2系で読み込むには
普通に3系で作ったもの(dump)だと2系では読み込め(load)ません
最初に書いたURLに書いてあるのですが、protocolを指定できるようです。
下記に各protocolバージョンの説明を載せときます

  • プロトコルバージョン 0 はオリジナルの「人間に判読可能な」プロトコルで、Python の初期のバージョンとの後方互換性を持ちます。
  • プロトコルバージョン 1 は旧形式のバイナリフォーマットで、これも Python の初期バージョンと互換性があります。
  • プロトコルバージョン 2 は Python 2.3 で導入されました。このバージョンでは 新方式のクラス のより効率的な pickle 化を提供しました。プロトコル 2 による改良に関する情報は PEP 307 を参照してください。
  • プロトコルバージョン 3 は Python 3.0 で追加されました。このバージョンで bytes オブジェクトをサポートしました。これは Python 2.x では非 pickle 化できません。これはデフォルトのプロトコルで、他の Python 3 バージョンとの互換性が求められる場合の推奨プロトコルです。
  • プロトコルバージョン 4 は Python 3.4 で追加されました。このバージョンでは巨大なオブジェクトのサポート、より多くの種類のオブジェクトの pickle 化、および一部のデータ形式の最適化が行われました。プロトコル 4 による改良に関する情報は PEP 3154 を参照してください。

python2系では、当然のごとくprotocolは2までしかないので、python3でもこれに合わせたほうがいいっぽい。(周りの人は、あまりpython2系をつかってないので)
見る限り、一番良さそうなのは4なので、自分だけが使う時にはこれ指定したほうが良さそうです。
ちなみに、デフォルトは3に設定されています。

##python3.5

pickle.dump
>>> pickle.dump(['あいうえお'], open('test.pkl','wb'), protocol=2 ) 

##python2.7

pickle.load
>>> pickle.load(open('test.pkl') ) 
[u'\u3042\u3044\u3046\u3048\u304a']  
>>> print(pickle.load(open('test.pkl') )[0] )
あいうえお           

#まとめ
'rb'つければ、なんとかなりそう(いまのところ)
ほかにも、fix_importserrorsのオプションがあるけど、とりあえずこれで動く。
動かない場面が出てきたら追記します。

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?