### 3 外部オブジェクトの pickle 化および unpickle 化

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

外部永続化 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 データ列中でオブジェクトに対する 参照を ``嗅ぎ回る'' ことができるようにするために存在しています 32。 リストに `persistent_load` を設定するやり方は、 よく Unpickler クラスの `noload()` メソッドと共に使われます。

#### Footnotes

... 上のユーザ定義関数にゆだねます 31
  ユーザ定義関数に関連付けを行うための実際のメカニズムは、 `pickle` および `cPickle` では少し異なります。 `pickle` のユーザは、サブクラス化を行い、 `persistend_id()` および `persistent_load()` メソッドを上書きすることで同じ効果を得ることができます
... ことができるようにするために存在しています 32
  Guide と Jim が居間に座り込んでピクルス (pickles) を 嗅いでいる光景を想像してください。