[python] TypeError: can’t pickle dict_keys objectsを解決する

 pickleは大変便利なライブラリですが、使っていると妙なエラーが発生することがあります。TypeError: can't pickle * objectsは、objectがpickleできませんよ、という意味ですから、他のオブジェクトに置換しない限りpickleすることが出来ません。

原因

 たとえば、こんなコードです。

d = {"a": "a", "b": "b", "c": "c"}
keys = d.keys()
pickle.dump(keys)  // -> [python] TypeError: can't pickle dict_keys objects

 ちなみに、values()でも似たようなことが起こりますね。

 keysはlistオブジェクトと思いきや、そっくりなだけのlist likeオブジェクトだったわけです。pickle互換の他のライブラリを使っても対応できません。どうすればいいのでしょうか。

対処法

 すごく単純な話で、対応しているオブジェクトに変換してやればいいのです。pythonのdict_keysオブジェクトは、多くの方はただのlistとして使っているはずです。然るに、

d = {"a": "a", "b": "b", "c": "c"}
keys = list(d.keys())
pickle.dump(keys)

 これだけでエラーが起きなくなります。結局のところ、根本的な原因を解決するにはオブジェクトを代替するしかないということです。

その他のTypeError: can’t pickle * objects

 実は、pickle互換のライブラリがいくつかあって、それらを使うことで解決出来たりもします。複数のライブラリについて検証した良い記事がありましたので紹介しておきます。

 Pythonのシリアライズモジュール pickle marshal dill cloudpickle を比較する

まとめ

  • cloudpickle使う
  • だめならオブジェクトを差し替える
  • それでもだめならシリアライズ処理を自分で書く…。