11.1. "pickle" --- Python オブジェクトの直列化
**********************************************

"pickle" モジュールでは、Python オブジェクトデータ構造を直列化
(serialize) したり非直列化 (de-serialize)するための基礎的ですが強力な
アルゴリズムを実装しています。 "Pickle 化 (Pickling)" は Python のオブ
ジェクト階層をバイトストリームに変換する過程を指します。"非 Pickle 化
(unpickling)" はその逆の操作で、バイトストリームをオブジェクト階層に戻
すように変換します。Pickle 化 (及び非 Pickle 化) は、別名 "直列化
(serialization)" や "整列化 (marshalling)" [1] 、 "平坦化
(flattening)" として知られていますが、ここでは混乱を避けるため、用語と
して "Pickle 化" および "非Pickle 化" を使います。

このドキュメントでは "pickle" モジュールおよび "cPickle" モジュールの
両方について記述します。

警告: "pickle" モジュールはエラーや不正に生成されたデータに対して安
  全では ありません。信頼できない、あるいは認証されていないソースから
  受け取っ たしたデータを unpickle してはいけません。


11.1.1. 他の Python モジュールとの関係
======================================

"pickle" モジュールには "cPickle" と呼ばれる最適化のなされた親類モジュ
ールがあります。名前が示すように、 "cPickle" は C で書かれており、この
ため "pickle" より 1000 倍くらいまで高速になる可能性があります。しかし
ながら "cPickle" では "Pickler()" および "Unpickler()" クラスのサブク
ラス化をサポートしていません。これは "cPickle" では、これらは関数であ
ってクラスではないからです。ほとんどのアプリケーションではこの機能は不
要であり、 "cPickle" の持つ高いパフォーマンスの恩恵を受けることができ
ます。その他の点では、二つのモジュールにおけるインタフェースはほとんど
同じです; このマニュアルでは共通のインタフェースを記述しており、必要に
応じてモジュール間の相違について指摘します。以下の議論では、 "pickle"
と "cPickle" の総称として "pickle" という用語を使うことにします。

これら二つのモジュールが生成するデータストリームは相互交換できることが
保証されています。

Python には "marshal" と呼ばれるより原始的な直列化モジュールがあります
が、一般的に Python オブジェクトを直列化する方法としては "pickle" を選
ぶべきです。 "marshal" は基本的に ".pyc" ファイルをサポートするために
存在しています。

"pickle" モジュールはいくつかの点で "marshal" と明確に異なります:

* "pickle" モジュールでは、同じオブジェクトが再度直列化されることの
  な いよう、すでに直列化されたオブジェクトについて追跡情報を保持しま
  す。 "marshal" はこれを行いません。

  この機能は再帰的オブジェクトと共有オブジェクトの両方に重要な関わりを
  もっています。再帰的オブジェクトとは自分自身に対する参照を持っている
  オブジェクトです。再帰的オブジェクトは marshal で扱うことができず、
  実際、再帰的オブジェクトを marshal 化しようとすると Python インタプ
  リタをクラッシュさせてしまいます。共有オブジェクトは、直列化しようと
  するオブジェクト階層の異なる複数の場所で同じオブジェクトに対する参照
  が存在する場合に生じます。共有オブジェクトを共有のままにしておくこと
  は、変更可能なオブジェクトの場合には非常に重要です。

* "marshal" はユーザ定義クラスやそのインスタンスを直列化するために使
  う ことができません。 "pickle" はクラスインスタンスを透過的に保存し
  たり 復元したりすることができますが、クラス定義をインポートすること
  が可能 で、かつオブジェクトが保存された際と同じモジュールで定義され
  ていなけ ればなりません。

* "marshal" の直列化フォーマットは Python の異なるバージョンで可搬性
  が あることを保証していません。 "marshal" の本来の仕事は ".pyc" ファ
  イ ルのサポートなので、Python を実装する人々には、必要に応じて直列化
  フ ォーマットを以前のバージョンと互換性のないものに変更する権限が残
  され ています。 "pickle" 直列化フォーマットには、全ての Python リリ
  ース間 で以前のバージョンとの互換性が保証されています。

直列化は永続化 (persisitence) よりも原始的な概念です; "pickle" はファ
イルオブジェクトを読み書きしますが、永続化されたオブジェクトの名前付け
問題や、(より複雑な) オブジェクトに対する競合アクセスの問題を扱いませ
ん。 "pickle" モジュールは複雑なオブジェクトをバイトストリームに変換す
ることができ、バイトストリームを変換前と同じ内部構造をオブジェクトに変
換することができます。このバイトストリームの最も明白な用途はファイルへ
の書き込みですが、その他にもネットワークを介して送信したり、データベー
スに記録したりすることができます。モジュール "shelve" はオブジェクトを
DBM 形式のデータベースファイル上で pickle 化したり unpickle 化したりす
るための単純なインタフェースを提供しています。


11.1.2. データストリームの形式
==============================

"pickle" が使うデータ形式は Python 特有です。そうすることで、XDR のよ
うな外部の標準が持つ制限 (例えば XDR ではポインタの共有を表現できませ
ん) を課せられることがないという利点があります; しかしこれは Python で
書かれていないプログラムが pickle 化された Python オブジェクトを再構築
できない可能性があることを意味します。

標準では、 "pickle" データ形式では印字可能な ASCII 表現を使います。こ
れはバイナリ表現よりも少しかさばるデータになります。印字可能な ASCII
の利用 (とその他の "pickle" 表現形式が持つ特徴) の大きな利点は、デバッ
グやリカバリを目的とした場合に、 pickle 化されたファイルを標準的なテキ
ストエディタで読めるということです。

現在、pickle化に使われるプロトコルは、以下の 3 種類です。

* バージョン 0 のプロトコルは、最初の ASCII プロトコルで、以前のバー
  ジ ョンのPython と後方互換です。

* バージョン 1 のプロトコルは、古いバイナリ形式で、以前のバージョン
  の Python と後方互換です。

* バージョン 2 のプロトコルは、Python 2.3 で導入されました。 *new-
  style class* を、より効率よく piclke 化します。

詳細は **PEP 307** を参照してください。

*protocol* を指定しない場合、プロトコル 0 が使われます。 *protocol* に
負値か "HIGHEST_PROTOCOL" を指定すると、有効なプロトコルの内、もっとも
高いバージョンのものが使われます。

バージョン 2.3 で変更: *protocol* パラメータが導入されました。

*protocol* version >= 1 を指定することで、少しだけ効率の高いバイナリ形
式を選ぶことができます。


11.1.3. 使用法
==============

オブジェクト階層を直列化するには、まず pickler を生成し、続いてpickler
の "dump()" メソッドを呼び出します。データストリームから非直列化するに
は、まず unpickler を生成し、続いて unpicklerの "load()" メソッドを呼
び出します。 "pickle" モジュールでは以下の定数を提供しています:

pickle.HIGHEST_PROTOCOL

   有効なプロトコルのうち、最も大きいバージョン。この値は、 *protocol*
   として渡せます。

   バージョン 2.3 で追加.

注釈: protocols >= 1 で作られた pickle ファイルは、常にバイナリモー
  ドでオ ープンするようにしてください。古い ASCII ベースの pickle プロ
  トコル 0 では、矛盾しない限りにおいてテキストモードとバイナリモード
  のいずれ も利用することができます。プロトコル 0 で書かれたバイナリの
  pickle ファイルは、行ターミネータとして単独の改行(LF)を含んでいて、
  ですので この形式をサポートしない、 Notepad や他のエディタで見たとき
  に「おか しく」見えるかもしれません。

この pickle 化の手続きを便利にするために、 "pickle" モジュールでは以下
の関数を提供しています:

pickle.dump(obj, file[, protocol])

   すでに開かれているファイルオブジェクト *file* に、 *obj* を pickle
   化したものを表現する文字列を書き込みます。 "Pickler(file,
   protocol).dump(obj)" と同じです。

   *protocol* を指定しない場合、プロトコル 0 が使われます。 *protocol*
   に負値か "HIGHEST_PROTOCOL" を指定すると、有効なプロトコルの内、も
   っとも高いバージョンのものが使われます。

   バージョン 2.3 で変更: *protocol* パラメータが導入されました。

   *file* は、単一の文字列引数を受理する "write()" メソッドを持たなけ
   ればなりません。従って、 *file* としては、書き込みのために開かれた
   ファイルオブジェクト、 "StringIO" オブジェクト、その他前述のインタ
   フェースに適合する他のカスタムオブジェクトをとることができます。

pickle.load(file)

   すでに開かれているファイルオブジェクト *file* から文字列を読み出し
   、読み出された文字列を pickle 化されたデータ列として解釈して、もと
   のオブジェクト階層を再構築して返します。 "Unpickler(file).load()"
   と同じです。

   *file* は、整数引数をとる "read()" メソッドと、引数の必要ない
   "readline()" メソッドを持たなければなりません。これらのメソッドは両
   方とも文字列を返さなければなりません。従って、 *file* としては、読
   み出しのために開かれたファイルオブジェクト、 "StringIO" オブジェク
   ト、その他前述のインタフェースに適合する他のカスタムオブジェクトを
   とることができます。

   この関数はデータ列の書き込まれているモードがバイナリかそうでないか
   を自動的に判断します。

pickle.dumps(obj[, protocol])

   *obj* の pickle 化された表現を、ファイルに書き込む代わりに文字列で
   返します。

   *protocol* を指定しない場合、プロトコル 0 が使われます。 *protocol*
   に負値か "HIGHEST_PROTOCOL" を指定すると、有効なプロトコルの内、も
   っとも高いバージョンのものが使われます。

   バージョン 2.3 で変更: *protocol* パラメータが追加されました。

pickle.loads(string)

   pickle 化されたオブジェクト階層を文字列から読み出します。文字列中で
   pickle 化されたオブジェクト表現よりも後に続く文字列は無視されます。

"pickle" モジュールでは、以下の 3 つの例外も定義しています:

exception pickle.PickleError

   下で定義されている他の例外で共通の基底クラスです。 "Exception" を継
   承しています。

exception pickle.PicklingError

   この例外は unpickle 不可能なオブジェクトが "dump()" メソッドに渡さ
   れた場合に送出されます。

exception pickle.UnpicklingError

   この例外は、オブジェクトを unpickle 化する際に問題が発生した場合に
   送出されます。 unpickle 化中には "AttributeError" 、 "EOFError" 、
   "ImportError" 、および "IndexError" といった他の例外 (これだけとは
   限りません) も発生する可能性があるので注意してください。

"pickle" モジュールでは、2 つの呼び出し可能オブジェクト [2] として、
"Pickler" および "Unpickler" を提供しています:

class pickle.Pickler(file[, protocol])

   pickle 化されたオブジェクトのデータ列を書き込むためのファイル類似の
   オブジェクトを引数にとります。

   *protocol* を指定しない場合、プロトコル 0 が使われます。 *protocol*
   に負値か "HIGHEST_PROTOCOL" を指定すると、有効なプロトコルの内、も
   っとも高いバージョンのものが使われます。

   バージョン 2.3 で変更: *protocol* パラメータが導入されました。

   *file* は単一の文字列引数を受理する "write()" メソッドを持たなけれ
   ばなりません。従って、 *file* としては、書き込みのために開かれたフ
   ァイルオブジェクト、 "StringIO" オブジェクト、その他前述のインタフ
   ェースに適合する他のカスタムオブジェクトをとることができます。

   "Pickler" オブジェクトでは、一つ (または二つ) の public なメソッド
   を定義しています:

   dump(obj)

      コンストラクタで与えられた、すでに開かれているファイルオブジェク
      トに *obj* の pickle 化された表現を書き込みます。コンストラクタ
      に渡された *protocol* 引数の値に応じて、バイナリおよびASCII 形式
      が使われます。

   clear_memo()

      picller の "メモ" を消去します。メモとは、共有オブジェクトまたは
      再帰的なオブジェクトが値ではなく参照で記憶されるようにするために
      、 pickler がこれまでどのオブジェクトに遭遇してきたかを記憶する
      データ構造です。このメソッドは pickler を再利用する際に便利です
      。

      注釈: Python 2.3 以前では、 "clear_memo()" は "cPickle" で生成
        された pickler でのみ利用可能でした。 "pickle" モジュールでは
        、 pickler は "memo" と呼ばれる Python 辞書型のインスタンス変
        数を 持ちます。従って、 "pickler" モジュールにおける pickler
        のメモ を消去は、以下のようにしてできます:

           mypickler.memo.clear()

        以前のバージョンの Python での動作をサポートする必要のないコー
        ドでは、単に "clear_memo()" を使ってください。

同じ "Pickler" のインスタンスに対し、 "dump()" メソッドを複数回呼び出
すことは可能です。この呼び出しは、対応する "Unpickler" インスタンスで
同じ回数だけ "load()" を呼び出す操作に対応します。同じオブジェクトが
"dump()" を複数回呼び出して pickle 化された場合、 "load()" は全て同じ
オブジェクトに対して参照を行います [3] 。

"Unpickler" オブジェクトは以下のように定義されています:

class pickle.Unpickler(file)

   pickle データ列を読み出すためのファイル類似のオブジェクトを引数に取
   ります。このクラスはデータ列がバイナリモードかどうかを自動的に判別
   します。従って、 "Pickler" のファクトリメソッドのようなフラグを必要
   としません。

   *file* は、整数引数をとる "read()" メソッドと、引数の必要ない
   "readline()" メソッドを持たなければなりません。これらのメソッドは両
   方とも文字列を返さなければなりません。従って、 *file* としては、読
   み出しのために開かれたファイルオブジェクト、 "StringIO" オブジェク
   ト、その他前述のインタフェースに適合する他のカスタムオブジェクトを
   とることができます。

   "Unpickler" オブジェクトは 1 つ (または 2 つ) の public なメソッド
   を持っています:

   load()

      コンストラクタで渡されたファイルオブジェクトからオブジェクトの
      pickle 化表現を読み出し、中に収められている再構築されたオブジェ
      クト階層を返します。

      このメソッドは自動的にデータストリームがバイナリモードで書き出さ
      れているかどうかを判別します。

   noload()

      "load()" に似ていますが、実際には何もオブジェクトを生成しないと
      いう点が違います。この関数は第一に pickle 化データ列中で参照され
      ている、"永続化 id" と呼ばれている値を検索する上で便利です。詳細
      は以下の pickle 化プロトコル を参照してください。

      **注意:** "noload()" メソッドは現在 "cPickle" モジュールで生成さ
      れた "Unpickler" オブジェクトのみで利用可能です。 "pickle" モジ
      ュールの "Unpickler" には、 "noload()" メソッドがありません。


11.1.4. 何を pickle 化したり unpickle 化できるのか?
===================================================

以下の型は pickle 化できます:

* "None" 、 "True" 、および "False"

* 整数、長整数、浮動小数点数、複素数

* 通常文字列および Unicode 文字列

* pickle 化可能なオブジェクトからなるタプル、リスト、集合および辞書

* モジュールのトップレベルで定義されている関数

* モジュールのトップレベルで定義されている組込み関数

* モジュールのトップレベルで定義されているクラス

* "__dict__" 属性を持つクラス、あるいは "__getstate__()" メソッドの
  返 り値が pickle 化可能なクラス (詳細は pickle 化プロトコル を参照)
  。

pickle 化できないオブジェクトを pickle 化しようとすると、
"PicklingError" 例外が送出されます; この例外が起きた場合、背後のファイ
ルには未知の長さのバイト列が書き込まれてしまいます。極端に再帰的なデー
タ構造を pickle 化しようとした場合には再帰の深さ制限を越えてしまうかも
しれず、この場合には "RuntimeError" が送出されます。この制限は、
"sys.setrecursionlimit()" で慎重に上げていくことは可能です。

(組み込みおよびユーザ定義の) 関数は、値ではなく "完全記述された" 参照
名として pickle 化されるので注意してください。これは、関数の定義されて
いるモジュールの名前と一緒と併せ、関数名だけが pickle 化されることを意
味します。関数のコードや関数の属性は何も pickle化されません。従って、
定義しているモジュールは unpickle 化環境で import 可能でなければならず
、そのモジュールには指定されたオブジェクトが含まれていなければなりませ
ん。そうでない場合、例外が送出されます [4] 。

クラスも同様に名前参照で pickle 化されるので、unpickle 化環境には同じ
制限が課せられます。クラス中のコードやデータは何も pickle 化されないの
で、以下の例ではクラス属性 "attr" が unpickle 化環境で復元されないこと
に注意してください

   class Foo:
       attr = 'a class attr'

   picklestring = pickle.dumps(Foo)

pickle 化可能な関数やクラスがモジュールのトップレベルで定義されていな
ければならないのはこれらの制限のためです。

同様に、クラスのインスタンスが pickle 化された際、そのクラスのコードお
よびデータはオブジェクトと一緒に pickle 化されることはありません。イン
スタンスのデータのみが pickle 化されます。この仕様は、クラス内のバグを
修正したりメソッドを追加した後でも、そのクラスの以前のバージョンで作ら
れたオブジェクトを読み出せるように意図的に行われています。あるクラスの
多くのバージョンで使われるような長命なオブジェクトを作ろうと計画してい
るなら、そのクラスの "__setstate__()" メソッドによって適切な変換が行わ
れるようにオブジェクトのバージョン番号を入れておくとよいかもしれません
。


11.1.5. pickle 化プロトコル
===========================

この節では pickler/unpickler と直列化対象のオブジェクトとの間のインタ
フェースを定義する "pickle 化プロトコル"について記述します。このプロト
コルは自分のオブジェクトがどのように直列化されたり非直列化されたりする
かを定義し、カスタマイズし、制御するための標準的な方法を提供します。こ
の節での記述は、unpickle 化環境を不信な pickle 化データに対して安全に
するために使う特殊なカスタマイズ化についてはカバーしていません; 詳細は
Unpickler をサブクラス化する を参照してください。


11.1.5.1. 通常のクラスインスタンスの pickle 化および unpickle 化
----------------------------------------------------------------

object.__getinitargs__()

   pickle 化されたクラスインスタンスが unpickle 化されたとき、
   "__init__()" メソッドは通常呼び出され *ません* 。 unpickle 化の際に
   "__init__()" が呼び出される方が望ましい場合、旧スタイルクラスではメ
   ソッド "__getinitargs__()" を定義することができます。 このメソッド
   はクラスコンストラクタ (例えば "__init__()") に渡されるべき位置引数
   からなる *タプル* を返さなければなりません。 "__getinitargs__()" メ
   ソッドは pickle 時に呼び出されます; この関数が返すタプルはインスタ
   ンスの pickle 化データに組み込まれます。

object.__getnewargs__()

   新スタイルクラスでは、プロトコル 2 で呼び出される
   "__getnewargs__()" を定義する事ができます。インスタンス生成時に内部
   的な不変条件が成立する必要があったり、（タプルや文字列のように）型
   の "__new__()" メソッドに指定する引数によってメモリの割り当てを変更
   する必要がある場合には "__getnewargs__()" を定義してください。新ス
   タイルクラス "C" のインスタンスは、次のように生成されます。:

      obj = C.__new__(C, *args)

   ここで *args* は元のオブジェクトの "__getnewargs__()" メソッドを呼
   び出した時の戻り値となります。 "__getnewargs__()" を定義していない
   場合、 *args* は空のタプルとなります。

object.__getstate__()

   クラスは、インスタンスの pickle 化方法にさらに影響を与えることがで
   きます; クラスが "__getstate__()" メソッドを定義している場合、この
   メソッドが呼び出され、返された状態値はインスタンスの内容として、イ
   ンスタンスの辞書の代わりに pickle 化されます。 "__getstate__()" メ
   ソッドが定義されていない場合、インスタンスの "__dict__" の内容が
   pickle 化されます。

object.__setstate__(state)

   unpickle 化では、クラスが "__setstate__()" も定義していた場合、
   unpickle 化された状態値とともに呼び出されます。 [5]
   "__setstate__()" メソッドが定義されていない場合、pickle 化された状
   態は辞書型でなければならず、その要素は新たなインスタンスの辞書に代
   入されます。クラスが "__getstate__()" と "__setstate__()" の両方を
   定義している場合、状態値オブジェクトは辞書である必要はなく、これら
   のメソッドは期待通りの動作を行います。 [6]

   注釈: 新しいスタイルのクラスにおいて "__getstate__()" が偽値を返
     す場合 、 "__setstate__()" メソッドは呼ばれません。

注釈: unpickleするとき、 "__getattr__()", "__getattribute__()",
  "__setattr__()" といったメソッドがインスタンスに対して呼ばれます。こ
  れらのメソッドが何か内部の不変条件に依存しているのであれば、その型は
  "__getinitargs__()" か "__getnewargs__()" のどちらかを実装してその不
  変条件を満たせるようにするべきです。それ以外の場合、 "__new__()" も
  "__init__()" も呼ばれません。


11.1.5.2. 拡張型の pickle 化および unpickle 化
----------------------------------------------

object.__reduce__()

   "Pickler" が全く未知の型の --- 拡張型のような --- オブジェクトに遭
   遇した場合、pickle 化方法のヒントとして 2 個所を探します。第一は
   "__reduce__()" メソッドを実装しているかどうかです。もし実装されてい
   れば、pickle 化時に "__reduce__()" メソッドが引数なしで呼び出されま
   す。メソッドはこの呼び出しに対して文字列またはタプルのどちらかを返
   さねばなりません。

   文字列を返す場合、その文字列は通常通りに pickle 化されるグローバル
   変数の名前を指しています。 "__reduce__()" の返す文字列は、モジュー
   ルにからみてオブジェクトのローカルな名前でなければなりません;
   pickle モジュールはモジュールの名前空間を検索して、オブジェクトの属
   するモジュールを決定します。

   タプルを返す場合、タプルの要素数は 2 から 5 でなければなりません。
   オプションの要素は省略したり "None" を指定したりできます。各要素の
   意味づけは以下の通りです:

   * オブジェクトの初期バージョンを生成するために呼び出される呼び出
     し 可能オブジェクトです。この呼び出し可能オブジェクトへの引数はタ
     プ ルの次の要素で与えられます。それ以降の要素では pickle 化された
     デ ータを完全に再構築するために使われる付加的な状態情報が与えられ
     ま す。

     逆 pickle 化の環境下では、このオブジェクトはクラスか、 "安全なコ
     ンストラクタ (safe constructor, 下記参照)" として登録されていたり
     属性 "__safe_for_unpickling__" の値が真であるような呼び出し可能オ
     ブジェクトでなければなりません。そうでない場合、逆 pickle 化を行
     う環境で "UnpicklingError" が送出されます。通常通り、 callable は
     名前だけで pickle 化されるので注意してください。

   * 呼び出し可能なオブジェクトのための引数からなるタプル

     バージョン 2.5 で変更: 以前は、この引数には "None" もあり得ました
     。

   * オプションとして、 通常のクラスインスタンスの pickle 化および
     unpickle 化 節で記述されているようにオブジェクトの
     "__setstate__()" メソッドに渡される、オブジェクトの状態。オブジェ
     クトが "__setstate__()" メソッドを持たない場合、上記のように、こ
     の値は辞書でなくてはならず、オブジェクトの "__dict__" に追加され
     ます。

   * オプションとして、リスト中の連続する要素を返すイテレータ (シー
     ケ ンスではありません)。このリストの要素は pickle 化され、
     "obj.append(item)" または "obj.extend(list_of_items)" のいずれか
     を使って追加されます。主にリストのサブクラスで用いられていますが
     、他のクラスでも、適切なシグネチャの "append()" や "extend()" を
     備えている限り利用できます。 ("append()" と "extend()" のいずれを
     使うかは、どのバージョンの pickle プロトコルを使っているか、そし
     て追加する要素の数で決まります。従って両方のメソッドをサポートし
     ていなければなりません。)

   * オプションとして、辞書中の連続する要素を返すイテレータ (シーケ
     ン スではありません)。このリストの要素は "(key, value)" という形
     式で なければなりません。要素は pickle 化され、 "obj[key] =
     value" を 使ってオブジェクトに格納されます。主に辞書のサブクラス
     で用いられ ていますが、他のクラスでも、 "__setitem__()" を備えて
     いる限り利用 できます。

object.__reduce_ex__(protocol)

   "__reduce__()" を実装する場合、プロトコルのバージョンを知っておくと
   便利なことがあります。これは "__reduce__()" の代わりに
   "__reduce_ex__()" を使って実現できます。 "__reduce_ex__()" が定義さ
   れている場合、 "__reduce__()" よりも優先して呼び出されます (以前の
   バージョンとの互換性のために "__reduce__()" を残しておいてもかまい
   ません)。 "__reduce_ex__()" はプロトコルのバージョンを表す整数の引
   数を一つ伴って呼び出されます。

   "object" クラスでは "__reduce__()" と "__reduce_ex__()" の両方を定
   義しています。とはいえ、サブクラスで "__reduce__()" をオーバライド
   しており、 "__reduce_ex__()" をオーバライドしていない場合には、
   "__reduce_ex__()" の実装がそれを検出して "__reduce__()" を呼び出す
   ようになっています。

pickle 化するオブジェクト上で "__reduce__()" メソッドを実装する代わり
に、 "copy_reg" モジュールを使って呼び出し可能オブジェクトを登録する方
法もあります。このモジュールはプログラムに "縮小化関数 (reduction
function)" とユーザ定義型のためのコンストラクタを登録する方法を提供し
ます。縮小化関数は、単一の引数として pickle 化するオブジェクトをとるこ
とを除き、上で述べた "__reduce__()" メソッドと同じ意味とインタフェース
を持ちます。

登録されたコンストラクタは上で述べたような unpickle 化については "安全
なコンストラクタ" であると考えられます。


11.1.5.3. 外部オブジェクトの pickle 化および unpickle 化
--------------------------------------------------------

オブジェクトの永続化を便利にするために、 "pickle" は pickle 化されたデ
ータ列上にないオブジェクトに対して参照を行うという概念をサポートしてい
ます。これらのオブジェクトは "永続化 id (persistent id)" で参照されて
おり、この id は単に印字可能なASCII 文字からなる任意の文字列です。これ
らの名前の解決方法は "pickle" モジュールでは定義されていません; オブジ
ェクトはこの名前解決を pickler および unpickler 上のユーザ定義関数にゆ
だねます [7] 。

外部永続化 id の解決を定義するには、pickler オブジェクトの
"persistent_id" 属性と、 unpickler オブジェクトの "persistent_load" 属
性を設定する必要があります。

外部永続化 id を持つオブジェクトを pickle 化するには、pickler は自作の
"persistent_id()" メソッドを持たなければなりません。このメソッドは一つ
の引数をとり、 "None" とオブジェクトの永続化 id のうちどちらかを返さな
ければなりません。 "None" が返された場合、 pickler は単にオブジェクト
を通常のように pickle 化するだけです。永続化 id 文字列が返された場合、
piclkler はその文字列に対して、unpickler がこの文字列を永続化 id とし
て認識できるように、マーカと共に pickle 化します。

外部オブジェクトを unpickle 化するには、unpickler は自作の
"persistent_load()" 関数を持たなければなりません。この関数は永続化 id
文字列を引数にとり、参照されているオブジェクトを返します。

*多分* より理解できるようになるようなちょっとした例を以下に示します:

   import pickle
   from cStringIO import StringIO

   src = StringIO()
   p = pickle.Pickler(src)

   def persistent_id(obj):
       if hasattr(obj, 'x'):
           return 'the value %d' % obj.x
       else:
           return None

   p.persistent_id = persistent_id

   class Integer:
       def __init__(self, x):
           self.x = x
       def __str__(self):
           return 'My name is integer %d' % self.x

   i = Integer(7)
   print i
   p.dump(i)

   datastream = src.getvalue()
   print repr(datastream)
   dst = StringIO(datastream)

   up = pickle.Unpickler(dst)

   class FancyInteger(Integer):
       def __str__(self):
           return 'I am the integer %d' % self.x

   def persistent_load(persid):
       if persid.startswith('the value '):
           value = int(persid.split()[2])
           return FancyInteger(value)
       else:
           raise pickle.UnpicklingError, 'Invalid persistent id'

   up.persistent_load = persistent_load

   j = up.load()
   print j

"cPickle" モジュール内では、 unpickler の "persistent_load" 属性は
Pythonリスト型として設定することができます。この場合、 unpickler が永
続化 id に遭遇しても、永続化 id 文字列は単にリストに追加されるだけです
。この仕様は、pickle データ中の全てのオブジェクトを実際にインスタンス
化しなくても、 pickle データ列中でオブジェクトに対する参照を "嗅ぎ回る
" ことができるようにするために存在しています [8] 。リストに
"persistent_load" を設定するやり方は、よく Unpickler クラスの
"noload()" メソッドと共に使われます。


11.1.6. Unpickler をサブクラス化する
====================================

デフォルトでは、逆 pickle 化は pickle 化されたデータ中に見つかったクラ
スを import することになります。自前の unpickler をカスタマイズするこ
とで、何が unpickle 化されて、どのメソッドが呼び出されるかを厳密に制御
することはできます。しかし不運なことに、厳密になにを行うべきかは
"pickle" と "cPickle" のどちらを使うかで異なります [9] 。

"pickle" モジュールでは、 "Unpickler" からサブクラスを派生し、
"load_global()" メソッドを上書きする必要があります。 "load_global()"
は pickle データ列から最初の 2 行を読まなければならず、ここで最初の行
はそのクラスを含むモジュールの名前、2 行目はそのインスタンスのクラス名
になるはずです。次にこのメソッドは、例えばモジュールをインポートして属
性を掘り起こすなどしてクラスを探し、発見されたものを unpickler のスタ
ックに置きます。その後、このクラスは空のクラスの "__class__" 属性に代
入する方法で、クラスの "__init__()" を使わずにインスタンスを魔法のよう
に生成します。あなたの作業は (もしその作業を受け入れるなら)、unpickler
のスタックの上に push された "load_global()" を、unpickle しても安全だ
と考えられる何らかのクラスの既知の安全なバージョンにすることです。ある
いは全てのインスタンスに対して unpickling を許可したくないならエラーを
送出してください。このからくりがハックのように思えるなら、あなたは間違
っていません。このからくりを動かすには、ソースコードを参照してください
。

"cPickle" では事情は多少すっきりしていますが、十分というわけではありま
せん。何を unpickle 化するかを制御するには、 unpickler の
"find_global" 属性を関数か "None" に設定します。属性が "None" の場合、
インスタンスを unpickle しようとする試みは全て "UnpicklingError" を送
出します。属性が関数の場合、この関数はモジュール名またはクラス名を受理
し、対応するクラスオブジェクトを返さなくてはなりません。このクラスが行
わなくてはならないのは、クラスの探索、必要な import のやり直しです。そ
してそのクラスのインスタンスが unpickle 化されるのを防ぐためにエラーを
送出することもできます。

以上の話から言えることは、アプリケーションが unpickle 化する文字列の発
信元については非常に高い注意をはらわなくてはならないということです。


11.1.7. 例
==========

いちばん単純には、 "dump()" と "load()" を使用してください。自己参照リ
ストが正しく pickle 化およびリストアされることに注目してください。

   import pickle

   data1 = {'a': [1, 2.0, 3, 4+6j],
            'b': ('string', u'Unicode string'),
            'c': None}

   selfref_list = [1, 2, 3]
   selfref_list.append(selfref_list)

   output = open('data.pkl', 'wb')

   # Pickle dictionary using protocol 0.
   pickle.dump(data1, output)

   # Pickle the list using the highest protocol available.
   pickle.dump(selfref_list, output, -1)

   output.close()

以下の例は pickle 化された結果のデータを読み込みます。 pickle を含むデ
ータを読み込む場合、ファイルはバイナリモードでオープンしなければいけま
せん。これは ASCII 形式とバイナリ形式のどちらが使われているかは分から
ないからです。

   import pprint, pickle

   pkl_file = open('data.pkl', 'rb')

   data1 = pickle.load(pkl_file)
   pprint.pprint(data1)

   data2 = pickle.load(pkl_file)
   pprint.pprint(data2)

   pkl_file.close()

より大きな例で、クラスを pickle 化する挙動を変更するやり方を示します。
"TextReader" クラスはテキストファイルを開き、 "readline()" メソッドが
呼ばれるたびに行番号と行の内容を返します。 "TextReader" インスタンスが
pickle 化された場合、ファイルオブジェクト *以外の* 全ての属性が保存さ
れます。インスタンスが unpickle 化された際、ファイルは再度開かれ、以前
のファイル位置から読み出しを再開します。上記の動作を実装するために、
"__setstate__()" および "__getstate__()" メソッドが使われています。

   #!/usr/local/bin/python

   class TextReader:
       """Print and number lines in a text file."""
       def __init__(self, file):
           self.file = file
           self.fh = open(file)
           self.lineno = 0

       def readline(self):
           self.lineno = self.lineno + 1
           line = self.fh.readline()
           if not line:
               return None
           if line.endswith("\n"):
               line = line[:-1]
           return "%d: %s" % (self.lineno, line)

       def __getstate__(self):
           odict = self.__dict__.copy() # copy the dict since we change it
           del odict['fh']              # remove filehandle entry
           return odict

       def __setstate__(self, dict):
           fh = open(dict['file'])      # reopen file
           count = dict['lineno']       # read from file...
           while count:                 # until line count is restored
               fh.readline()
               count = count - 1
           self.__dict__.update(dict)   # update attributes
           self.fh = fh                 # save the file object

使用例は以下のようになるでしょう:

   >>> import TextReader
   >>> obj = TextReader.TextReader("TextReader.py")
   >>> obj.readline()
   '1: #!/usr/local/bin/python'
   >>> obj.readline()
   '2: '
   >>> obj.readline()
   '3: class TextReader:'
   >>> import pickle
   >>> pickle.dump(obj, open('save.p', 'wb'))

"pickle" が Python プロセス間でうまく働くことを見たいなら、先に進む前
に他の Python セッションを開始してください。以下の振る舞いは同じプロセ
スでも新たなプロセスでも起こります。

   >>> import pickle
   >>> reader = pickle.load(open('save.p', 'rb'))
   >>> reader.readline()
   '4:     """Print and number lines in a text file."""'

参考:

  "copy_reg" モジュール
     拡張型を登録するための Pickle インタフェース構成機構。

  "shelve" モジュール
     オブジェクトのインデクス付きデータベース; "pickle" を使います。

  "copy" モジュール
     オブジェクトの浅いコピーおよび深いコピー。

  "marshal" モジュール
     組み込み型の高性能な直列化。


11.2. "cPickle" --- より高速な "pickle"
***************************************

"cPickle" モジュールは Python オブジェクトの直列化および非直列化をサポ
ートし、 "pickle" モジュールとほとんど同じインタフェースと機能を提供し
ます。いくつか相違点がありますが、最も重要な違いはパフォーマンスとサブ
クラス化が可能かどうかです。

第一に、 "cPickle" は C で実装されているため、 "pickle" よりも最大で
1000 倍高速です。第二に、 "cPickle" モジュール内では、呼び出し可能オブ
ジェクト "Pickler()" および "Unpickler()" は関数で、クラスではありませ
ん。つまり、pickle 化や unpickle 化を行うカスタムのサブクラスを派生す
ることができないということです。多くのアプリケーションではこの機能は不
要なので、 "cPickle" モジュールによる大きなパフォーマンス向上の恩恵を
受けられるはずです。

"pickle" と "cPickle" で作られた pickle データ列は同じなので、既存の
pickle データに対して "pickle" と "cPickle" を互換に使用することができ
ます。 [10]

"cPickle" と "pickle" の API 間には他にも些細な相違がありますが、ほと
んどのアプリケーションで互換性があります。より詳細なドキュメンテーショ
ンは "pickle" のドキュメントにあり、そこでドキュメント化されている相違
点について挙げています。

-[ 脚注 ]-

[1] "marshal" モジュールと間違えないように注意してください。

[2] "pickle" では、これらの呼び出し可能オブジェクトはクラスであり
    、サ ブクラス化してその動作をカスタマイズすることができます。しか
    し、 "cPickle" モジュールでは、これらの呼び出し可能オブジェクトは
    ファク トリ関数であり、サブクラス化することができません。サブクラ
    スを作成 する共通の理由の一つは、どのオブジェクトを実際に unpickle
    するかを 制御することです。詳細については Unpickler をサブクラス化
    する を参 照してください。

[3] *警告*: これは、複数のオブジェクトを pickle 化する際に、オブジ
    ェク トやそれらの一部に対する変更を妨げないようにするための仕様で
    す。あ るオブジェクトに変更を加えて、その後同じ "Pickler" を使って
    再度 pickle 化しようとしても、そのオブジェクトは pickle 化しなおさ
    れま せん --- そのオブジェクトに対する参照が pickle 化され、
    "Unpickler" は変更された値ではなく、元の値を返します。これには 2
    つの問題点 : (1) 変更の検出、そして (2) 最小限の変更を整列化するこ
    と、があります。ガーベジコレクションもまた問題になります。

[4] 送出される例外は "ImportError" や "AttributeError" になるはず
    です が、他の例外も起こりえます。

[5] これらのメソッドはクラスインスタンスのコピーを実装する際にも用
    いら れます。

[6] このプロトコルはまた、 "copy" で定義されている浅いコピーや深い
    コピ ー操作でも用いられます。

[7] ユーザ定義関数に関連付けを行うための実際のメカニズムは、
    "pickle" および "cPickle" では少し異なります。 "pickle" のユーザは
    、サブク ラス化を行い、 "persistend_id()" および
    "persistent_load()" メソッ ドを上書きすることで同じ効果を得ること
    ができます。

[8] Guide と Jim が居間に座り込んでピクルス (pickles) を嗅いでいる
    光景 を想像してください。

[9] 注意してください: ここで記述されている機構は内部の属性とメソッ
    ドを 使っており、これらはPython の将来のバージョンで変更される対象
    にな っています。われわれは将来、この挙動を制御するための、
    "pickle" お よび "cPickle" の両方で動作する、共通のインタフェース
    を提供するつ もりです。

[10] pickle データ形式は実際には小規模なスタック指向のプログラム
     言語で あり、またあるオブジェクトをエンコードする際に多少の自由度
     がある ため、二つのモジュールが同じ入力オブジェクトに対して異なる
     データ 列を生成することもあります。しかし、常に互いに他のデータ列
     を読み 出せることが保証されています。
