11.1. pickle — Pythonオブジェクトのシリアル化—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/2.7/library/pickle
移動先:案内検索

11.1。 漬物 —Pythonオブジェクトのシリアル化

pickle モジュールは、Pythonオブジェクト構造をシリアル化および逆シリアル化するための基本的で強力なアルゴリズムを実装します。 「ピクリング」は、Pythonオブジェクト階層がバイトストリームに変換されるプロセスであり、「アンピクリング」は、バイトストリームがオブジェクト階層に変換される逆の操作です。 酸洗い(および酸洗い解除)は、「シリアル化」、「マーシャリング」、 1 、または「平坦化」とも呼ばれますが、混乱を避けるために、ここで使用される用語は「酸洗い」および「酸洗い解除」です。

このドキュメントでは、 pickle モジュールと cPickle モジュールの両方について説明します。

警告

pickle モジュールは、誤ったデータや悪意を持って作成されたデータに対して安全ではありません。 信頼できない、または認証されていないソースから受信したデータを盗み取らないでください。


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

pickle モジュールには、 cPickle モジュールと呼ばれる最適化されたいとこがあります。 その名前が示すように、 cPickle はCで記述されているため、 pickle よりも最大1000倍高速になる可能性があります。 ただし、 Pickler()および Unpickler()クラスのサブクラス化はサポートされていません。これは、 cPickle では、これらはクラスではなく関数であるためです。 ほとんどのアプリケーションはこの機能を必要とせず、 cPickle のパフォーマンスの向上から恩恵を受けることができます。 それ以外は、2つのモジュールのインターフェースはほぼ同じです。 共通のインターフェースはこのマニュアルで説明されており、必要に応じて違いが指摘されています。 以下の説明では、「pickle」という用語を使用して、 pickle モジュールと cPickle モジュールをまとめて説明します。

2つのモジュールが生成するデータストリームは交換可能であることが保証されています。

Pythonには marshal と呼ばれるより原始的なシリアル化モジュールがありますが、一般に pickle は常にPythonオブジェクトをシリアル化するための推奨される方法です。 marshal は、主にPythonの.pycファイルをサポートするために存在します。

pickle モジュールは、 marshal といくつかの重要な点で異なります。

  • pickle モジュールは、すでにシリアル化されているオブジェクトを追跡するため、後で同じオブジェクトへの参照が再度シリアル化されることはありません。 marshal はこれを行いません。

    これは、再帰オブジェクトとオブジェクト共有の両方に影響します。 再帰オブジェクトは、それ自体への参照を含むオブジェクトです。 これらはマーシャルによって処理されません。実際、再帰オブジェクトをマーシャリングしようとすると、Pythonインタープリターがクラッシュします。 オブジェクト共有は、シリアル化されるオブジェクト階層の異なる場所に同じオブジェクトへの複数の参照がある場合に発生します。 pickle は、そのようなオブジェクトを1回だけ格納し、他のすべての参照がマスターコピーを指すようにします。 共有オブジェクトは共有されたままです。これは、可変オブジェクトにとって非常に重要な場合があります。

  • marshal を使用して、ユーザー定義クラスとそのインスタンスをシリアル化することはできません。 pickle は、クラスインスタンスを透過的に保存および復元できますが、クラス定義はインポート可能であり、オブジェクトが保存されたときと同じモジュールに存在する必要があります。

  • marshal シリアル化形式は、Pythonバージョン間での移植性が保証されていません。 人生の主な仕事は.pycファイルをサポートすることであるため、Pythonの実装者は、必要に応じて下位互換性のない方法でシリアル化形式を変更する権利を留保します。 pickle シリアル化形式は、Pythonリリース間で下位互換性があることが保証されています。

シリアル化は永続性よりも原始的な概念であることに注意してください。 pickle はファイルオブジェクトの読み取りと書き込みを行いますが、永続オブジェクトの命名の問題や、永続オブジェクトへの同時アクセスの(さらに複雑な)問題は処理しません。 pickle モジュールは、複雑なオブジェクトをバイトストリームに変換し、バイトストリームを同じ内部構造を持つオブジェクトに変換できます。 おそらく、これらのバイトストリームで最も明白なことは、ファイルに書き込むことですが、ネットワークを介して送信したり、データベースに保存したりすることも考えられます。 モジュール shelve は、DBMスタイルのデータベースファイル上のオブジェクトをピクルスおよびピクルス解除するためのシンプルなインターフェイスを提供します。


11.1.2。 データストリーム形式

pickle で使用されるデータ形式はPython固有です。 これには、XDR(ポインター共有を表すことができない)などの外部標準によって課せられる制限がないという利点があります。 ただし、これは、Python以外のプログラムがpickle化されたPythonオブジェクトを再構築できない可能性があることを意味します。

デフォルトでは、 pickle データ形式は印刷可能なASCII表現を使用します。 これは、バイナリ表現よりもわずかにボリュームがあります。 印刷可能なASCII(および pickle の表現の他のいくつかの特性)を使用することの大きな利点は、デバッグまたは回復の目的で、人間が標準のテキストエディターでpickle化されたファイルを読み取ることができることです。

現在、酸洗いに使用できる3つの異なるプロトコルがあります。

  • プロトコルバージョン0は元のASCIIプロトコルであり、以前のバージョンのPythonと下位互換性があります。
  • プロトコルバージョン1は、以前のバージョンのPythonとも互換性のある古いバイナリ形式です。
  • プロトコルバージョン2はPython2.3で導入されました。 新しいスタイルのクラス esのはるかに効率的な酸洗いを提供します。

詳細については、 PEP 307 を参照してください。

protocol が指定されていない場合、プロトコル0が使用されます。 protocol が負の値として指定されている場合、または HIGHEST_PROTOCOL が指定されている場合は、使用可能な最高のプロトコルバージョンが使用されます。

バージョン2.3で変更: プロトコルパラメーターが導入されました。


protocol バージョン> = 1を指定することで、少し効率的なバイナリ形式を選択できます。


11.1.3。 使用法

オブジェクト階層をシリアル化するには、最初にピクラーを作成してから、ピクラーの dump()メソッドを呼び出します。 データストリームを逆シリアル化するには、最初にunpicklerを作成し、次にunpicklerの load()メソッドを呼び出します。 pickle モジュールは、次の定数を提供します。

pickle.HIGHEST_PROTOCOL

利用可能な最高のプロトコルバージョン。 この値は、プロトコル値として渡すことができます。

バージョン2.3の新機能。

ノート

プロトコル> = 1で作成されたpickleファイルは必ずバイナリモードで開いてください。 古いASCIIベースのpickleプロトコル0の場合、一貫性が保たれている限り、テキストモードまたはバイナリモードのいずれかを使用できます。

バイナリモードでプロトコル0で記述されたpickleファイルには、ラインターミネータとして単独のラインフィードが含まれるため、メモ帳やこの形式をサポートしていない他のエディタで表示すると「おかしい」ように見えます。


pickle モジュールは、酸洗いプロセスをより便利にするために次の機能を提供します。

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

obj のpickle化された表現を開いているファイルオブジェクト file に書き込みます。 これはPickler(file, protocol).dump(obj)と同等です。

protocol パラメーターを省略すると、プロトコル0が使用されます。 protocol が負の値として指定されている場合、または HIGHEST_PROTOCOL が指定されている場合は、最も高いプロトコルバージョンが使用されます。

バージョン2.3で変更: プロトコルパラメーターが導入されました。

file には、単一の文字列引数を受け入れるwrite()メソッドが必要です。 したがって、書き込み用に開かれたファイルオブジェクト、 StringIO オブジェクト、またはこのインターフェイスを満たすその他のカスタムオブジェクトにすることができます。

pickle.load(file)

開いているファイルオブジェクトファイルから文字列を読み取り、それをpickleデータストリームとして解釈し、元のオブジェクト階層を再構築して返します。 これはUnpickler(file).load()と同等です。

file には、整数引数をとるread()メソッドと、引数を必要としない readline()メソッドの2つのメソッドが必要です。 どちらのメソッドも文字列を返す必要があります。 したがって、 file は、読み取り用に開かれたファイルオブジェクト、 StringIO オブジェクト、またはこのインターフェイスを満たすその他のカスタムオブジェクトにすることができます。

この関数は、データストリームがバイナリモードで書き込まれたかどうかを自動的に判別します。

pickle.dumps(obj[, protocol])

オブジェクトのpickle化された表現を、ファイルに書き込むのではなく、文字列として返します。

protocol パラメーターを省略すると、プロトコル0が使用されます。 protocol が負の値として指定されている場合、または HIGHEST_PROTOCOL が指定されている場合は、最も高いプロトコルバージョンが使用されます。

バージョン2.3で変更: プロトコルパラメーターが追加されました。

pickle.loads(string)
文字列からpickle化されたオブジェクト階層を読み取ります。 ピクルス化されたオブジェクトの表現を超えた文字列内の文字は無視されます。

pickle モジュールでは、次の3つの例外も定義されています。

exception pickle.PickleError
以下に定義されている他の例外の共通基本クラス。 これはExceptionから継承します。
exception pickle.PicklingError
この例外は、選択できないオブジェクトが dump()メソッドに渡された場合に発生します。
exception pickle.UnpicklingError
この例外は、オブジェクトの選択解除に問題がある場合に発生します。 AttributeErrorEOFErrorImportErrorIndexErrorなど、他の例外もピッキング解除中に発生する可能性があることに注意してください。

pickle モジュールは、2つの呼び出し可能オブジェクト 2Pickler および Unpickler もエクスポートします。

class pickle.Pickler(file[, protocol])

これは、pickleデータストリームを書き込むファイルのようなオブジェクトを取ります。

protocol パラメーターを省略すると、プロトコル0が使用されます。 protocol が負の値として指定されている場合、または HIGHEST_PROTOCOL が指定されている場合は、最も高いプロトコルバージョンが使用されます。

バージョン2.3で変更: プロトコルパラメーターが導入されました。

file には、単一の文字列引数を受け入れるwrite()メソッドが必要です。 したがって、開いているファイルオブジェクト、 StringIO オブジェクト、またはこのインターフェイスを満たすその他のカスタムオブジェクトにすることができます。

Pickler オブジェクトは、1つ(または2つ)のパブリックメソッドを定義します。

dump(obj)

obj のpickle化された表現を、コンストラクターで指定された開いているファイルオブジェクトに書き込みます。 コンストラクターに渡される protocol 引数の値に応じて、バイナリ形式またはASCII形式のいずれかが使用されます。

clear_memo()

ピッカーの「メモ」をクリアします。 メモは、ピッカーがすでに見たオブジェクトを記憶するデータ構造であるため、共有オブジェクトまたは再帰オブジェクトは、値ではなく参照によってピクルされます。 この方法は、ピッカーを再利用するときに役立ちます。

ノート

Python 2.3より前は、 clear_memo()は、 cPickle によって作成されたピッカーでのみ使用可能でした。 pickle モジュールでは、ピッカーにはPython辞書であるmemoというインスタンス変数があります。 したがって、 pickle モジュールピッカーのメモをクリアするには、次のようにします。

mypickler.memo.clear()

古いバージョンのPythonをサポートする必要のないコードは、単に clear_memo()を使用する必要があります。

同じ Pickler インスタンスの dump()メソッドを複数回呼び出すことができます。 次に、これらは、対応する Unpickler インスタンスの load()メソッドへの同じ数の呼び出しと一致する必要があります。 同じオブジェクトが複数の dump()呼び出しによってピクルス化された場合、 load()はすべて同じオブジェクトへの参照を生成します。 3

Unpickler オブジェクトは次のように定義されます。

class pickle.Unpickler(file)

これは、pickleデータストリームを読み取るファイルのようなオブジェクトを取得します。 このクラスは、データストリームがバイナリモードで書き込まれたかどうかを自動的に判断するため、 Pickler ファクトリのようにフラグは必要ありません。

file には、整数引数をとるread()メソッドと、引数を必要としない readline()メソッドの2つのメソッドが必要です。 どちらのメソッドも文字列を返す必要があります。 したがって、 file は、読み取り用に開かれたファイルオブジェクト、 StringIO オブジェクト、またはこのインターフェイスを満たすその他のカスタムオブジェクトにすることができます。

Unpickler オブジェクトには、1つ(または2つ)のパブリックメソッドがあります。

load()

コンストラクターで指定されたオープンファイルオブジェクトからpickle化されたオブジェクト表現を読み取り、そこで指定された再構成されたオブジェクト階層を返します。

このメソッドは、データストリームがバイナリモードで書き込まれたかどうかを自動的に判断します。

noload()

これは、実際にはオブジェクトを作成しないことを除けば、 load()と同じです。 これは主に、pickleデータストリームで参照される可能性のある「永続ID」と呼ばれるものを見つけるのに役立ちます。 詳細については、以下のセクションピクルスプロトコルを参照してください。

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


11.1.4。 何を漬けたり、漬けたりすることができますか?

以下のタイプを漬けることができます:

  • NoneTrue、およびFalse
  • 整数、長整数、浮動小数点数、複素数
  • 通常のUnicode文字列
  • 選択可能なオブジェクトのみを含むタプル、リスト、セット、および辞書
  • モジュールのトップレベルで定義された関数
  • モジュールのトップレベルで定義された組み込み関数
  • モジュールのトップレベルで定義されているクラス
  • __ dict __ または__getstate__()を呼び出した結果がpickle化可能なクラスのインスタンス(詳細については、セクション pickleプロトコルを参照)。

ピクルできないオブジェクトをピクルしようとすると、 PicklingError 例外が発生します。 これが発生した場合、不特定のバイト数が基になるファイルにすでに書き込まれている可能性があります。 再帰性の高いデータ構造をピクルスしようとすると、最大再帰深度を超える可能性があります。この場合、RuntimeErrorが発生します。 sys.setrecursionlimit()を使用して、この制限を慎重に引き上げることができます。

関数(組み込みおよびユーザー定義)は、値ではなく、「完全修飾」の名前参照によって選択されることに注意してください。 これは、関数が定義されているモジュールの名前とともに、関数名のみがpickle化されることを意味します。 関数のコードもその関数属性もpickle化されていません。 したがって、定義モジュールはピッキング解除環境にインポート可能である必要があり、モジュールには名前付きオブジェクトが含まれている必要があります。そうでない場合、例外が発生します。 4

同様に、クラスは名前付き参照によってピクルされるため、ピクル解除環境でも同じ制限が適用されます。 クラスのコードまたはデータはいずれもピクルされていないため、次の例では、クラス属性attrはピクル解除環境では復元されないことに注意してください。

class Foo:
    attr = 'a class attr'

picklestring = pickle.dumps(Foo)

これらの制限により、選択可能な関数とクラスをモジュールのトップレベルで定義する必要があります。

同様に、クラスインスタンスがピクルされる場合、それらのクラスのコードとデータはそれらと一緒にピクルされません。 インスタンスデータのみがピクルされます。 これは意図的に行われるため、クラスのバグを修正したり、クラスにメソッドを追加したりしても、以前のバージョンのクラスで作成されたオブジェクトを読み込むことができます。 クラスの多くのバージョンを表示する長寿命のオブジェクトを計画している場合は、クラスの__setstate__()メソッドで適切な変換を行えるように、オブジェクトにバージョン番号を付けることをお勧めします。


11.1.5。 ピクルスプロトコル

このセクションでは、ピクラー/アンピッカーとシリアル化されるオブジェクトとの間のインターフェースを定義する「ピクルスプロトコル」について説明します。 このプロトコルは、オブジェクトのシリアル化および逆シリアル化の方法を定義、カスタマイズ、および制御するための標準的な方法を提供します。 このセクションの説明では、信頼できないピクルスデータストリームからピクルス解除環境をわずかに安全にするために採用できる特定のカスタマイズについては説明していません。 詳細については、セクション Unpicklersのサブクラス化を参照してください。

11.1.5.1。 通常のクラスインスタンスのpickle化とunpickling

object.__getinitargs__()
ピクルされたクラスインスタンスがピクルされていない場合、その __ init __()メソッドは通常呼び出されません。 ピクリング解除時に __ init __()メソッドを呼び出すことが望ましい場合、古いスタイルのクラスでメソッド __ getinitargs __()を定義できます。このメソッドは、タプルを返す必要があります。 ]クラスコンストラクターに渡される位置引数( __ init __()など)。 キーワード引数はサポートされていません。 __ getinitargs __()メソッドはピクルス時に呼び出されます。 返されるタプルは、インスタンスのピクルスに組み込まれます。
object.__getnewargs__()

新しいスタイルのタイプは、プロトコル2に使用される __ getnewargs __()メソッドを提供できます。 このメソッドの実装は、インスタンスの作成時に型が内部不変条件を確立する場合、またはメモリ割り当てが型の __ new __()メソッドに渡される値の影響を受ける場合に必要です(タプルの場合と同様)。および文字列)。 新しいスタイルのクラス Cのインスタンスは、

obj = C.__new__(C, *args)

ここで、 args は、元のオブジェクトで __ getnewargs __()を呼び出した結果です。 __ getnewargs __()がない場合は、空のタプルと見なされます。

object.__getstate__()
クラスは、インスタンスのピクル化方法にさらに影響を与える可能性があります。 クラスがメソッド __ getstate __()を定義している場合、そのクラスが呼び出され、インスタンスのディクショナリのコンテンツではなく、インスタンスのコンテンツとして戻り状態が選択されます。 __ getstate __()メソッドがない場合、インスタンスの __ dict __ がpickle化されます。
object.__setstate__(state)

選択解除時に、クラスがメソッド __ setstate __()も定義している場合、選択解除された状態で呼び出されます。 5 __ setstate __()メソッドがない場合、pickle化された状態はディクショナリである必要があり、そのアイテムは新しいインスタンスのディクショナリに割り当てられます。 クラスが __ getstate __()__ setstate __()の両方を定義する場合、状態オブジェクトはディクショナリである必要はなく、これらのメソッドは必要な処理を実行できます。 6

ノート

新しいスタイルのクラス esの場合、 __ getstate __()がfalse値を返すと、 __ setstate __()メソッドは呼び出されません。

ノート

選択解除時に、__getattr__()__getattribute__()、または__setattr__()などの一部のメソッドがインスタンスで呼び出される場合があります。 これらのメソッドが内部不変条件がtrueであることに依存している場合、型は__getinitargs__()または__getnewargs__()のいずれかを実装してそのような不変条件を確立する必要があります。 それ以外の場合、__new__()__init__()も呼び出されません。


11.1.5.2。 拡張タイプのピクルスおよびピクルス解除

object.__reduce__()

Picklerは、拡張タイプなど、何も知らないタイプのオブジェクトに遭遇すると、それをピクルスにする方法のヒントを2か所で探します。 1つの代替方法は、オブジェクトが __ reduce __()メソッドを実装することです。 提供されている場合、ピクルス時に __ reduce __()が引数なしで呼び出され、文字列またはタプルのいずれかを返す必要があります。

文字列が返される場合、その内容は通常どおりピクルス化されるグローバル変数に名前が付けられます。 __ reduce __()によって返される文字列は、そのモジュールに関連するオブジェクトのローカル名である必要があります。 pickleモジュールは、モジュールの名前空間を検索して、オブジェクトのモジュールを判別します。

タプルが返されるとき、それは2から5要素の長さでなければなりません。 オプションの要素は省略できます。または、値としてNoneを指定できます。 このタプルの内容は通常どおりピクルス化され、ピクルス解除時にオブジェクトを再構築するために使用されます。 各要素のセマンティクスは次のとおりです。

  • オブジェクトの初期バージョンを作成するために呼び出される呼び出し可能オブジェクト。 タプルの次の要素は、この呼び出し可能オブジェクトの引数を提供し、後の要素は、ピクルス化されたデータを完全に再構築するために後で使用される追加の状態情報を提供します。

    選択解除環境では、このオブジェクトはクラス、「安全なコンストラクター」として登録された呼び出し可能オブジェクト(以下を参照)、または真の値を持つ属性__safe_for_unpickling__を持っている必要があります。 それ以外の場合、UnpicklingErrorはピッキング解除環境で発生します。 いつものように、呼び出し可能オブジェクト自体は名前でピクルスになっていることに注意してください。

  • 呼び出し可能オブジェクトの引数のタプル。

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

  • オプションで、オブジェクトの状態。これは、セクション通常のクラスインスタンスのピクルスとアンピッキングで説明されているように、オブジェクトの __ setstate __()メソッドに渡されます。 オブジェクトに __ setstate __()メソッドがない場合、上記のように、値はディクショナリである必要があり、オブジェクトの __ dict __ に追加されます。

  • オプションで、連続するリスト項目を生成するイテレータ(シーケンスではない)。 これらのリストアイテムはピクルス化され、obj.append(item)またはobj.extend(list_of_items)のいずれかを使用してオブジェクトに追加されます。 これは主にリストサブクラスに使用されますが、適切な署名を持つappend()およびextend()メソッドがある限り、他のクラスでも使用できます。 (append()またはextend()のどちらを使用するかは、使用するピクルスプロトコルのバージョンと追加するアイテムの数によって異なるため、両方をサポートする必要があります。)

  • オプションで、(key, value)の形式のタプルである必要がある、連続する辞書項目を生成するイテレーター(シーケンスではない)。 これらのアイテムは、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 __()[X266X ]。

ピクルス化するオブジェクトに__reduce__()メソッドを実装する代わりに、呼び出し可能オブジェクトを copy_reg モジュールに登録することもできます。 このモジュールは、プログラムが「削減関数」とユーザー定義型のコンストラクターを登録する方法を提供します。 リダクション関数は、上記の__reduce__()メソッドと同じセマンティクスとインターフェイスを備えていますが、ピクルス化されるオブジェクトである単一の引数で呼び出される点が異なります。

登録されたコンストラクターは、上記のように選択を解除する目的で「安全なコンストラクター」と見なされます。


11.1.5.3。 外部オブジェクトのピクルスとピクルス解除

オブジェクトの永続性を確保するために、 pickle モジュールは、pickle化されたデータストリームの外部にあるオブジェクトへの参照の概念をサポートしています。 このようなオブジェクトは、印刷可能なASCII文字の任意の文字列である「永続ID」によって参照されます。 このような名前の解決は、 pickle モジュールでは定義されていません。 この解決策を、ピッカーとアンピッカーのユーザー定義関数に委任します。 7

外部永続ID解決を定義するには、ピクラーオブジェクトのpersistent_id属性とアンピッカーオブジェクトのpersistent_load属性を設定する必要があります。

外部永続IDを持つオブジェクトをpickle化するには、ピッカーは、オブジェクトを引数として受け取り、Noneまたはそのオブジェクトの永続IDのいずれかを返すカスタムpersistent_id()メソッドを持っている必要があります。 Noneが返されると、ピッカーは通常どおりオブジェクトをピクルスします。 永続ID文字列が返されると、ピクラーはマーカーとともにその文字列をピクルスにして、ピクラー解除者がその文字列を永続IDとして認識するようにします。

外部オブジェクトの選択を解除するには、選択解除機能に、永続ID文字列を取得して参照されるオブジェクトを返すカスタムpersistent_load()関数が必要です。

がより多くの光を当てる可能性があるというばかげた例を次に示します。

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文字列が単純に追加されます。このリスト。 この機能は、ピクルス内のすべてのオブジェクトを実際にインスタンス化することなく、ピクルスデータストリームをオブジェクト参照に対して「スニッフィング」できるようにするために存在します。 8 persistent_loadをリストに設定することは、通常、Unpicklerのnoload()メソッドと組み合わせて使用されます。


11.1.6。 Unpicklersのサブクラス化

デフォルトでは、ピクルス解除は、ピクルスデータで見つかったすべてのクラスをインポートします。 unpicklerをカスタマイズすることで、何が選択解除され、何が呼び出されるかを正確に制御できます。 残念ながら、これを行う方法は、 picklecPickle のどちらを使用しているかによって異なります。 9

pickle モジュールでは、load_global()メソッドをオーバーライドする必要があります。 load_global()は、pickleデータストリームから2行を読み取る必要があります。最初の行はクラスを含むモジュールの名前で、2番目の行はインスタンスのクラスの名前です。 次に、クラスを検索し、場合によってはモジュールをインポートして属性を掘り出し、見つかったものをアンピッカーのスタックに追加します。 後で、このクラスは、クラスの__init__()を呼び出さずにインスタンスを魔法のように作成する方法として、空のクラスの__class__属性に割り当てられます。 あなたの仕事(あなたがそれを受け入れることを選択した場合)は、load_global()をピクラーのスタックにプッシュさせることです。これは、ピクルスを外しても安全だと思われるクラスの既知の安全なバージョンです。 そのようなクラスを作成するのはあなた次第です。 または、インスタンスのすべての選択解除を禁止する場合は、エラーが発生する可能性があります。 これがハックのように聞こえるなら、あなたは正しいです。 これを機能させるには、ソースコードを参照してください。

cPickle を使用すると、状況は少しきれいになりますが、それほどではありません。 選択解除されるものを制御するには、選択解除者のfind_global属性を関数またはNoneに設定します。 Noneの場合、インスタンスの選択を解除しようとすると、UnpicklingErrorが発生します。 関数の場合は、モジュール名とクラス名を受け入れ、対応するクラスオブジェクトを返す必要があります。 クラスを検索し、必要なインポートを実行する責任があり、クラスのインスタンスが選択解除されないようにするためにエラーが発生する可能性があります。

この話の教訓は、アプリケーションが解き放つ文字列のソースに本当に注意する必要があるということです。


11.1.7。 例

最も単純なコードの場合は、dump()およびload()関数を使用します。 自己参照リストが選択され、正しく復元されることに注意してください。

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化されたデータを読み取ります。 ピクルスを含むファイルを読み取るときは、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()

これは、クラスのピクルス動作を変更する方法を示す大きな例です。 TextReaderクラスはテキストファイルを開き、readline()メソッドが呼び出されるたびに行番号と行の内容を返します。 TextReaderインスタンスがpickle化されると、ファイルオブジェクトメンバーを除くすべての属性が保存されます。 インスタンスの選択が解除されると、ファイルが再度開かれ、最後の場所から読み取りが再開されます。 __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インターフェースコンストラクター登録。
モジュールシェルフ
オブジェクトのインデックス付きデータベース。 picle を使用します。
モジュールコピー
浅くて深いオブジェクトのコピー。
モジュールマーシャル
組み込み型の高性能シリアル化。


11.2。 cPickle —より高速漬物

cPickle モジュールは、Pythonオブジェクトのシリアル化と逆シリアル化をサポートし、 pickle モジュールとほぼ同じインターフェイスと機能を提供します。 いくつかの違いがありますが、最も重要なのはパフォーマンスとサブクラス化です。

まず、 cPickle は、 pickle よりも最大1000倍高速である可能性があります。これは、前者がCで実装されているためです。 次に、 cPickle モジュールでは、呼び出し可能オブジェクトPickler()およびUnpickler()は関数であり、クラスではありません。 これは、それらを使用してカスタムのピクルスおよびピクルス解除サブクラスを導出できないことを意味します。 ほとんどのアプリケーションはこの機能を必要とせず、 cPickle モジュールの大幅に改善されたパフォーマンスの恩恵を受けるはずです。

picklecPickle によって生成されるpickleデータストリームは同一であるため、 picklecPickle を既存のpickleと互換的に使用できます。 10

cPicklepickle のAPIには追加の小さな違いがありますが、ほとんどのアプリケーションでは互換性があります。 その他のドキュメントは、 pickle モジュールのドキュメントに記載されています。このドキュメントには、ドキュメント化された違いのリストが含まれています。

脚注

1
これをマーシャルモジュールと混同しないでください
2
pickle モジュールでは、これらの呼び出し可能オブジェクトはクラスであり、サブクラス化して動作をカスタマイズできます。 ただし、 cPickle モジュールでは、これらの呼び出し可能関数はファクトリ関数であるため、サブクラス化することはできません。 サブクラス化する一般的な理由の1つは、実際に選択解除できるオブジェクトを制御することです。 詳細については、セクション Unpicklersのサブクラス化を参照してください。
3
警告:これは、オブジェクトまたはそのパーツに変更を加えることなく、複数のオブジェクトをピクルスにすることを目的としています。 オブジェクトを変更してから、同じPicklerインスタンスを使用して再度ピクルする場合、オブジェクトは再度ピクルされません。オブジェクトへの参照がピクルされ、Unpicklerは古い値を返します。変更されたもの。 ここには2つの問題があります。(1)変更を検出すること、および(2)最小限の変更セットをマーシャリングすることです。 ガベージコレクションもここで問題になる可能性があります。
4
発生する例外は、ImportErrorまたはAttributeErrorである可能性がありますが、それ以外の可能性があります。
5
これらのメソッドは、クラスインスタンスのコピーを実装するためにも使用できます。
6
このプロトコルは、 copy モジュールで定義されている浅いコピー操作と深いコピー操作でも使用されます。
7
これらのユーザー定義関数を関連付ける実際のメカニズムは、 picklecPickle では少し異なります。 ここでの説明は、両方の実装で同じように機能します。 pickle モジュールのユーザーは、サブクラス化を使用して同じ結果を生成し、派生クラスのpersistent_id()メソッドとpersistent_load()メソッドをオーバーライドすることもできます。
8
リビングルームでピクルスを嗅ぎながら座っているグイドとジムの画像を残しておきます。
9
注意:ここで説明するメカニズムは、Pythonの将来のバージョンで変更される可能性のある内部属性とメソッドを使用します。 いつの日か、この動作を制御するための共通インターフェースを提供する予定です。これは、 pickle または cPickle のいずれかで機能します。
10
ピクルスデータ形式は実際には小さなスタック指向プログラミング言語であり、特定のオブジェクトのエンコーディングにはある程度の自由度があるため、2つのモジュールが同じ入力オブジェクトに対して異なるデータストリームを生成する可能性があります。 ただし、常に互いのデータストリームを読み取ることができることが保証されています。