pickleでエラーならdillで保存する!【Python】

python

Pythonのpickleを使うと、いろいろなデータを保存出来て便利ですよね。
しかし、ファイルオブジェクトやlambda関数を含むようなオブジェクトを保存するときにはエラーが出てしまいます。

例えばlambda関数を使う例として、defaultdictを保存しようとする例を挙げます。

>>> from collections import defaultdict
>>> d = defaultdict(lambda:0)
>>> import pickle
>>> pickle.dumps(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7f3d780b6e18>: attribute lookup <lambda> on __main__ failed

ここでは、辞書にないキーを参照すると「0」を返すような辞書”d”を、lambda関数を使って作成しています。

これをpickle.dumpを用いてシリアライズすると、上のようなエラーが出てしまいます。

また、ファイルなどを読み込んでdumpしようとすると、Type:Errorが出てしまいます。

 

dillを使って保存する。

そんな時にはdillを使って保存しましょう!
dillはpickleと全く同じ使い方ができる上に、pickleで保存できないようなオブジェクトを保存することができます。
普段からpickleを使っている方であれば、pickleを単純にdillに置き換えるだけで上記のようなエラーを回避することができます。

dillはpipを使って以下のようにインストールすることができます。

$ pip install dill

 

dillで保存

dillでの保存にはdill.dumpを使用します。
使い方は以下の通りです。

dill.dump(保存する変数, open(保存するパス,’wb’))

実際に保存する手続きを以下に示します。
上で作成した辞書”d”を保存します。

>>> import dill
>>> dill.dump(d, open('dictionary.dill','wb'))

上の例では、defaultdictで作成した辞書を’dictionary.dill’という名前で保存しています。
pickleの時とは違い、エラーが出ずに保存ができていることを確認してください。
また、このときopenのオプションを”wb”とすることに注意してください。

ちなみに、wbはバイナリを保存するオプションで、dumpsでは一度辞書をバイナリに変換してから保存を行います。
実際に保存されるバイナリは、dumpsを用いて確認することができます。

>>> dill.dumps(d)
b'\x80\x03ccollections\ndefaultdict\nq\x00cdill.dill\n_create_function\nq\x01(cdill.dill\n_load_type\nq\x02X\x08\x00\x00\x00CodeTypeq\x03\x85q\x04Rq\x05(K\x00K\x00K\x00K\x01KCC\x04d\x01S\x00q\x06NK\x00\x86q\x07))X\x07\x00\x00\x00<stdin>q\x08X\x08\x00\x00\x00<lambda>q\tK\x01C\x00q\n))tq\x0bRq\x0cc__builtin__\n__main__\nh\tNN}q\rtq\x0eRq\x0f\x85q\x10Rq\x11.'

出力の先頭には、バイナリ文字列を表すbが付与されていることを確認してください。

 

dillで読み込み

dillでの読み込みも、pickle同様に行うことができます。
先ほど保存したdictionary.dillを読み込むときは、以下のようにします。

>>> d = dill.load(open('dictionary.dill','rb'))

ここで、openのオプションを「rb」にすることを忘れないようにしてください。
rbはバイナリを読み込むオプションで、loadはバイナリをもとのオブジェクトに復元する働きを持っています。

dumpsと同様、バイナリを直接読み込むloads(loadではないことに注意!)についても確認します。

>>> d_binary = dill.dumps(d) # バイナリ化
>>> d2 = dill.loads(d_binary) # バイナリを復元
>>> d==d2
True

dumpsで辞書をバイナリ化した後、loadsで復元できていることが確認できます。
あまり使わないかもしれませんが、挙動を確認しておくことは大事ですよね!

 

python
1
【WP REST API解説】投稿を更新する(POST /posts/id)

Word PressのAPIを用いてすでに投稿されている記事を更新する方法について説明します。 あわ …

python
【対処法】pip install mecab-python3のエラー

久しぶりに自然言語処理の環境を一から作るとき、形態素解析器MeCabのインストールでコケることがよく …

python
【WP REST API解説】投稿を取得する(GET /posts/id)

Word PressのAPIを用いて投稿内容を取得する方法について説明します。 あわせて、Pytho …