3.7 Standard Module pickle

       

pickleモジュールは、基本的かつ強力な ピクリング(いわゆる、シリアライジング、マーシャリング、 フラタニング) と呼ばれるアルゴリズムを提供します。 このアルゴリズムは、 ほとんどすべてのPythonオブジェクトを 文字列表現に変換します。文字列表現から、オブジェクトを再構成 するのは、アンピクリングです。 ピクリングは、データの永続保存よりも、ずっとプリミティブな概念です。 というのは、pickleはファイルオブジェクトを読んだり書き出したり しますが、その永続化されたオブジェクトにどんな名前をつけるかとか、 同時にアクセスした場合の処理の問題については 扱っていません。 pickleモジュールは複雑な構造のオブジェクトを文字列表現に変換し、 文字列表現を、(文字列表現変換前と)同じ内部構造をもつ オブジェクトに変換します。 これらの文字列表現に関して行うこととして明らかに言えることは、 その文字列表現をファイル上に書くということです。 当然、ネットワークを経由して送信されたり、データベースに格納されたりも されるでしょう。shelveモジュールは、``dbm''形式のデータベースファイル 上に、オブジェクトをpickleしたり、unpickleしたりします。  

注意: pickle モジュールは実行速度がかなり遅いです。 同じアルゴリズムをC言語で再実装したcPickleモジュールは、 1000倍速いです。このモジュールは、PicklerUnpickler が関数であってクラスではないことを除けば同じインターフェースを備えています。 (関数であるため、継承のためのベースクラスとして使用することができません)

組み込みモジュールの marshalとは異なり, pickle は以下 について正しく扱います。  

pickleが用いるデータフォーマットは Python特有のものです。 このため、 XDR(共有ポインタを表現できない)    のような外部標準によって データフォーマットが制約される ということがないという利点があります。 しかしながら、非パイソンのプログラムでは、ピクル化されたパイソンオブジェクトを 再構成できないことになります。

デフォルトでは、ピクルデータのフォーマットは印字可能なASCII表現を 使用します。この場合、バイナリ表現よりも少しデータ量が大きくなります。 印字可能なASCII文字とピクルの表現のために使用される他のいくつかの文字 を使う 大きな利点は、デバッグや復旧を目的に、 ピクル化されたファイルを標準的なテキストエディタで 読むことが可能であることです。

バイナリのフォーマットは、上記で示したASCII表現よりも 少し効率的な表現です。Picklerのコンストラクタや dump()dumps()関数の引数 binに非0(真)の値を与えることによって バイナリフォーマットにすることができます。 バイナリフォーマットは、パイソン1.4のpickleモジュールと互換性が ないためにデフォルトではありません。 将来のバージョンで、デフォルトがバイナリに変更される可能性はあります。

pickleモジュールは、marshalと違って コードオブジェクトは扱いません。 pickleモジュールでも、コードオブジェクトを処理することは可能であり、 またそうするべきであるとは思いますが、今すぐに必要というわけでは ないというのがコードオブジェクトを扱わない理由だと思われます (marshalがコードオブジェクトの読み書きに使用されている限り)。 そして少なくともこの理由のため、トロイアの木馬がプログラムの中に入り込む のを避けているのです。  

pickleを使って書かれた永続モジュールのために、 ピックルされた文字列表現の外部のオブジェクトに対する参照の概念を サポートしています。 そのようなオブジェクトは、印字可能なASCII文字から構成される 任意の文字列の名前によって参照されます。 このとき、名前の解決はpickleモジュールによって定義されていません。 そこで、永続オブジェクトはpersistent_load()メソッドを実装しておく 必要があります。永続オブジェクトへの参照を書くために、 永続モジュールは Noneまたはオブジェクトの永続IDを 返すpersistent_id()メソッドを定義しなければならないのです。

クラスインスタンスをピクリングする上でいくつかの制限があります。

何よりもまず、クラスはモジュール内のトップレベルで定義されていなければ なりません。さらに、インスタンス変数の全てはピクル可能でなければなりません。

ピクルされたクラスインスタンスがアンピクルされるとき、 その__init__()メソッドは通常実行されません。 注意:これは、本モジュールの前バージョンの仕様とは異なります。 Python 1.5b2からこのように変更になりました。変更の理由は、 引数を伴うコンストラクタをもつことが多く、__getinitargs__() メソッドを実装しなければならないのは面倒だからです。

アンピクル時に、__init__()メソッドをコールする必要がある 場合には、クラスは__getinitargs__()メソッドを定義しなければ なりません。このメソッドは、クラスのコンストラクタ(__init__()) が呼び出されるときの引数を含むタプルを返します。 このメソッドは、ピクル時にコールされます。 そのときに返されたタプルはインスタンスをピクルしたときにその内部に 埋めこまれます。   

クラスは、そのインスタンスがいかにピクルされるかということに 大きな影響を与えることができます。 クラスが__getstate__()メソッドを定義している場合、 ピクル時にそのメソッドがコールされ、返却されたステータスが インスタンスの内容としてピクルされます。 クラスが__setstate__()メソッドを定義している場合、 __getstate__()メソッドによって設定されたステータスを引数に __setstate__()メソッドがコールされます。 (これらのメソッドはクラスインスタンスをコピーするときに 使用することができることに注目して下さい。) クラスに__getstate__() メソッドがない場合、 インスタンスの__dict__属性がピクルされます。 クラスに__setstate__()メソッドがない場合、 ピクルされたオブジェクトは辞書であり、その要素は新しいインスタンスの 辞書に割り当てられます。 (クラスが__getstate__()__setstate__()の 両メソッドを定義している場合には、ステータスのオブジェクトは 必ずしも辞書である必要はありません(好きなようにコーディングできます)。 このプロトコルは、copyモジュールにて定義されている 浅いコピーと深いコピーを行う演算にて使用されています。     

クラスインスタンスがピクルされるとき、 クラスのコード(クラスを定義するコード)とデータ(クラス変数)は ピクルされないことに注意して下さい。 インスタンスデータだけがピクル されます。 これは、クラスのバグフィックスやメソッドの追加を行った後で、 古いバージョンのクラスによって作成されたオブジェクトをロード (アンピクル)できるようにするためです。 クラスのバージョンがたくさん変わるほど長く存在することを想定された オブジェクトの場合、クラスの__setstate__()メソッドで 相応しい変換(アンピクル)を行うことを目的に オブジェクトの内部にバージョン番号を埋め込むことは、 価値があるでしょう。

クラス自身がピクルされる場合は、 その名前だけがピクルされます。すなわち、クラス定義は ピクルされすに、アンピクルの過程で再インポートされます。 ゆえに、クラスはモジュール内のトップレベルで定義されなければならない という制限は、ピクルされるクラスにも同様に当てはまります。

インターフェース概要を以下に示します。

オブジェクト x をファイル fにピクルするために、 次のオープンおよび書き込みを行います:

p = pickle.Pickler(f)
p.dump(x)

この簡略版は次のようになります:

pickle.dump(x, f)

ファイル fからオブジェクトx をアンピクルするために、次のオープンおよび読み込みを行います:

u = pickle.Unpickler(f)
x = u.load()

簡略版は以下になります:

x = pickle.load(f)

Picklerクラスは、文字列の引数でf.write() メソッドをコールします。Unpicklerクラスは、 整数の引数でf.read()メソッドを、引数なしで f.readline()メソッドをコールして、両メソッドともに 文字列を返します。 It is explicitly allowed to pass non-file objects here, as long as they have the right methods.   

Picklerクラスのコンストラクタは、オプションで2番目の引数binを 指定できます。この引数が指定されて非0のとき、バイナリピクルフォーマットが 使用されます。引数が 0 または与えられない場合は、 (データ容量的に効率的な表現ではないが、互換性のある)テキストピクルフォーマット が使用されます。Unpicklerクラスは、バイナリフォーマットと テキストフォーマットを区別すrための引数は持っていません。両フォーマットに 対応しています。

以下のタイプがピクル可能です:

ピクル不可能なオブジェクトをピクルしようとしたときには、 例外PicklingErrorが上げられます。 when this happens, an unspecified number of bytes may have been written to the file.

同一のPicklerインスタンスでメソッドdump() を複数回実行することは可能です。 この場合、dump()の実行を行うごとに、Picklerインスタンス と対になる Unpicklerインスタンスのload()メソッドを 実行させなければなりません。 同一のオブジェクトに対して、dump()によるピクリングが 複数回行われる場合には、load()は全て同一オブジェクトへの参照を 作成することになります。 警告: this is intended for pickling multiple objects without intervening modifications to the objects or their parts. もし仮に同じPicklerインスタンスを用いて オブジェクトを変更後再びピクルしても、 オブジェクトは再度ピクリングされません。 オブジェクトへの参照がピクリングされ、Unpicklerは 変更後のオブジェクトではなく変更前のオブジェクトを返すのです。 (There are two problems here: (a) detecting changes, and (b) marshalling a minimal set of changes. I have no answers. Garbage Collection may also become a problem here.)

PicklerUnpicklerクラスとは別に、 本モジュールは以下の関数とひとつの例外を定義しています:

dump (object, file[, bin])
オープンしたファイルオブジェクトfileobectのピクル表現を書きます。 これは、"Pickler(file, bin).dump(object)" と等価です。 オプションの引数binが与えられて非0の場合、バイナリピクルフォーマット が使用されます。0または無視された場合は、やや非効率な保存形式である テキストピクルフォーマットが使用されます。

load (file)
オープンしたファイルオブジェクトfileから ピクルオブジェクトを読みます。 これは、"Unpickler(file).load()" と等価です。

dumps (object[, bin])
オブジェクトのピクル表現をファイルに書くかわりに文字列で返します。 オプションの引数binが与えられて非0の場合、バイナリピクルフォーマット が使用されます。0または無視された場合は、やや非効率な保存形式である テキストピクルフォーマットが使用されます。

loads (string)
ファイルのかわりに文字列からピクルオブジェクトを読みます。 ピクルのオブジェクト表現ではない文字は無視されます。

PicklingError
ピクル不可能なオブジェクトをPickler.dump()にて与えた場合に この例外が上げられます。

See Also:

モジュール copy_reg    (pickle interface constructor registration)

モジュール shelve    (オブジェクトのインデックスデータベース; pickleを使用します)

モジュール copy    (オブジェクトの浅い深いコピー)

モジュール marshal    (組み込みタイプの高パフォーマンスなシリアライズ)

guido@python.org