オブジェクトの保存(データの永続性) [重複] 質問する

オブジェクトの保存(データの永続性) [重複] 質問する

次のようなオブジェクトを作成しました:

company1.name = 'banana' 
company1.value = 40

このオブジェクトを保存したいのですが、どうすればよいですか?

ベストアンサー1

あなたはpickle標準ライブラリのモジュール。以下は、この例への基本的な適用例です。

import pickle

class Company(object):
    def __init__(self, name, value):
        self.name = name
        self.value = value

with open('company_data.pkl', 'wb') as outp:
    company1 = Company('banana', 40)
    pickle.dump(company1, outp, pickle.HIGHEST_PROTOCOL)

    company2 = Company('spam', 42)
    pickle.dump(company2, outp, pickle.HIGHEST_PROTOCOL)

del company1
del company2

with open('company_data.pkl', 'rb') as inp:
    company1 = pickle.load(inp)
    print(company1.name)  # -> banana
    print(company1.value)  # -> 40

    company2 = pickle.load(inp)
    print(company2.name) # -> spam
    print(company2.value)  # -> 42

ファイルを開いて単一のオブジェクトを書き込む次のような独自のシンプルなユーティリティを定義することもできます。

def save_object(obj, filename):
    with open(filename, 'wb') as outp:  # Overwrites any existing file.
        pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)

# sample usage
save_object(company1, 'company1.pkl')

アップデート

これは非常に人気のある回答なので、少し高度な使用方法についていくつか触れたいと思います。

cPickle(または_pickle)対pickle

ほとんどの場合、実際にcPickleモジュールではなく、pickle前者は C で書かれていて、はるかに高速であるためです。両者の間には微妙な違いがありますが、ほとんどの場合は同等であり、C バージョンの方がはるかに優れたパフォーマンスを提供します。切り替えは非常に簡単で、ステートメントをimport次のように変更するだけです。

import cPickle as pickle

Python 3では は にcPickle名前が変更されましたが、モジュールが自動的に行うようになった_pickleため、これを行う必要はなくなりました。picklePython 3 の pickle と _pickle の違いは何ですか?

要約すると、Python 2 と 3 の両方で C バージョンが利用可能な場合に、コードが常にC バージョンを使用するようにするには、次のようなものを使用できます。

try:
    import cPickle as pickle
except ModuleNotFoundError:
    import pickle

データ ストリーム形式 (プロトコル)

picklePython固有のさまざまなフォーマット(プロトコルと呼ばれる)でファイルを読み書きすることができます。ドキュメンテーション「プロトコル バージョン 0」は ASCII なので「人間が読める」ものです。0 より大きいバージョンはバイナリで、使用可能な最高バージョンは使用している Python のバージョンによって異なります。デフォルトも Python のバージョンによって異なります。Python 2 ではデフォルトはプロトコル バージョン でした0が、Python 3.8.1 ではプロトコル バージョン です4。Python 3.x ではモジュールpickle.DEFAULT_PROTOCOLに が追加されましたが、Python 2 には存在しません。

幸いなことに、すべての呼び出しで記述するための省略形がありますpickle.HIGHEST_PROTOCOL(それが目的であると仮定し、通常はそうします)。リテラル番号を使用するだけです-1。これは、負のインデックスを介してシーケンスの最後の要素を参照するのと似ています。したがって、次のように記述する代わりに:

pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)

次のように書くこともできます:

pickle.dump(obj, outp, -1)

Picklerどちらの場合でも、複数の pickle 操作で使用するオブジェクトを作成する場合は、プロトコルを 1 回だけ指定する必要があります。

pickler = pickle.Pickler(outp, -1)
pickler.dump(obj1)
pickler.dump(obj2)
   etc...

: 異なるバージョンの Python を実行している環境の場合は、おそらく、すべてのバージョンで読み取ることができる特定のプロトコル番号を明示的に使用 (つまり、ハードコード) する必要があります (新しいバージョンでは通常、以前のバージョンで作成されたファイルを読み取ることができます)。

複数のオブジェクト

上記のサンプルに示すように、pickle ファイルには任意の数の pickle オブジェクトを含めることができますが、オブジェクトの数が不明な場合は、、、または などlistの可変サイズのコンテナーにすべてのオブジェクトを保存し、1 回の呼び出しですべてのオブジェクトをファイルに書き込む方が簡単な場合がよくあります。tupledict

tech_companies = [
    Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')

後でリストとその中のすべてを次のように復元します。

with open('tech_companies.pkl', 'rb') as inp:
    tech_companies = pickle.load(inp)

主な利点は、後で読み込むために保存されているオブジェクトインスタンスの数を知る必要がないことです(その情報なしでも実行できますが少し特殊なコードが必要です)。関連する質問の回答を参照してください。複数のオブジェクトを pickle ファイルに保存して読み込みますか?さまざまな方法についてはこちらをご覧ください。個人的には@Lutz Precheltの答え最善の方法は、以下のサンプル コードで使用されているアプローチです。

class Company:
    def __init__(self, name, value):
        self.name = name
        self.value = value

def pickle_loader(filename):
    """ Deserialize a file of pickled objects. """
    with open(filename, "rb") as f:
        while True:
            try:
                yield pickle.load(f)
            except EOFError:
                break

print('Companies in pickle file:')
for company in pickle_loader('company_data.pkl'):
    print('  name: {}, value: {}'.format(company.name, company.value))

おすすめ記事