Python Pickle モジュール

Python 開発では、実行時のオブジェクトを保存したり、プログラム再起動後に以前の状態を復元したりする必要がよくあります。例:

  • 計算結果をディスクにキャッシュして、重複計算を避ける
  • ユーザー設定やプログラムの中間状態を保存する
  • 異なる Python プロセス間で複雑なオブジェクトを渡す

pickleモジュールはまさに、Python がこのような問題を解決するために提供しているものです公式の組み込みソリューション。

Python のpickleモジュールは、Python オブジェクトのシリアライズとデシリアライズを行うための標準ライブラリモジュールです。

Pickle を使い始める前に、2 つの中心的な概念を理解する必要があります:

  • シリアライズ(Pickling):Python オブジェクトをバイト列に変換します
  • デシリアライズ(Unpickling):バイト列を Python オブジェクトに戻します

pickleモジュールは、ほぼすべての Python オブジェクト(リスト、辞書、クラスインスタンスなど)をファイルに保存したり、ネットワーク経由で転送したりして、必要なときに再読み込みできます。

なぜ Pickle モジュールを使うのか?

  1. データの永続化:Python オブジェクトをファイルに保存して、プログラム終了後もこれらのデータにアクセスできるようにします。
  2. データ転送:ネットワーク経由で Python オブジェクトを転送します。例えば、分散システムでデータを渡す場合などです。
  3. 高速な保存と読み込み:pickleモジュールは複雑なデータ構造を効率的に処理できるため、高速な保存と読み込みが必要なシーンに適しています。

Pickle の典型的な使用シーン

pickle以下のようなシーンに非常に適しています:

  1. ローカルデータの永続化
  2. プログラムの実行状態の保存と復元
  3. 中間計算結果のキャッシュ
  4. Python プロセス間通信(IPC)
  5. 機械学習モデルや特徴データの保存

適さないシーン:

  • 言語をまたぐデータ交換
  • フロントエンドとバックエンドのインターフェースでのデータ転送
  • 信頼できないデータソースのデシリアライズ

Pickle はどのようなオブジェクトをサポートしていますか?

1. サポートされているオブジェクトの型

型 サポートの有無
int / float / bool / str サポート
list / tuple / dict / set サポート
None サポート
カスタムクラスのインスタンス サポート
ネスト構造 サポート

サポートされない、または推奨されないオブジェクト

  • 開いているファイルオブジェクト
  • socket、データベース接続
  • オペレーティングシステムのリソース
  • 実行環境の状態に依存するオブジェクト

モジュールのインポート

Pickle モジュールの使用は非常に簡単で、インポートするだけです:

import pickle

Pickle モジュールの基本的な使い方

1. オブジェクトのシリアライズ

使用するpickle.dump()メソッドで Python オブジェクトをシリアライズしてファイルに保存できます。

例

import pickle

# Python オブジェクトを作成
data = {
    'name': 'Alice',
    'age': 25,
    'hobbies': ['reading', 'traveling']
}

# オブジェクトをシリアライズしてファイルに保存
with open('data.pkl', 'wb') as file:
    pickle.dump(data, file)
  • 'wb'バイナリ書き込みモードでファイルを開くことを表します。
  • pickle.dump() 将 dataオブジェクトをシリアライズしてファイルに書き込みます。

2. オブジェクトのデシリアライズ

使用するpickle.load()メソッドでファイルから Python オブジェクトを読み込んでデシリアライズできます。

例

import pickle

# ファイルからオブジェクトを読み込んでデシリアライズ
with open('data.pkl', 'rb') as file:
    loaded_data = pickle.load(file)

print(loaded_data)
  • 'rb'バイナリ読み取りモードでファイルを開くことを表します。
  • pickle.load()ファイルからバイトストリームを読み取り、Python オブジェクトにデシリアライズします。

3. バイト列へのシリアライズ

ファイルに保存したくない場合は、pickle.dumps() を使ってオブジェクトをバイト列にシリアライズできます:

例

import pickle

data = [1, 2, 3, 4, 5]

# バイト列にシリアライズ
byte_data = pickle.dumps(data)
print(byte_data)
# 出力例: b'\x80\x04\x95\x0f\x00\x00\x00...'

4. バイト列からのデシリアライズ

pickle.loads() を使うと、バイト列からオブジェクトをデシリアライズできます:

例

import pickle

byte_data = b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02K\x03K\x04K\x05e.'

# バイト列からデシリアライズ
original_data = pickle.loads(byte_data)
print(original_data)
# 出力: [1, 2, 3, 4, 5]

5. シリアライズ可能なオブジェクトの型

Pickle はほとんどの Python オブジェクトをシリアライズできます。以下を含みます:

  • 基本データ型:整数、浮動小数点数、文字列、ブール値、None
  • コレクション型:リスト、タプル、辞書、セット
  • カスタムクラスのインスタンス
  • 関数とクラス(一定の制限あり)

例

import pickle

# 異なる型のデータをシリアライズ
numbers = [1, 2, 3]
text = "Hello, Pickle"
dictionary = {'key': 'value'}
tuple_data = (1, 2, 3)
set_data = {1, 2, 3}

# すべてのデータを1つのリストに入れる
all_data = [numbers, text, dictionary, tuple_data, set_data]

# シリアライズ
with open('mixed_data.pkl', 'wb') as f:
    pickle.dump(all_data, f)

# デシリアライズ
with open('mixed_data.pkl', 'rb') as f:
    loaded_data = pickle.load(f)
    print(loaded_data)

6. カスタムクラスのシリアライズ

Pickle はカスタムクラスのインスタンスをうまく処理できます:

例

import pickle

class Student:
    def __init__(self, name, age, grade):
        self.name = name
        self.age = age
        self.grade = grade
   
    def __repr__(self):
        return f"Student(name={self.name}, age={self.age}, grade={self.grade})"

# インスタンスを作成
student = Student("李四", 20, "大三")

# シリアライズ
with open('student.pkl', 'wb') as f:
    pickle.dump(student, f)

# デシリアライズ
with open('student.pkl', 'rb') as f:
    loaded_student = pickle.load(f)
    print(loaded_student)
    # 出力: Student(name=李四, age=20, grade=大三)

7. 複数オブジェクトのシリアライズ

pickle.dump() を複数回呼び出して、複数のオブジェクトを保存できます:

例

import pickle

data1 = {'item': 'apple', 'count': 5}
data2 = ['banana', 'orange', 'grape']
data3 = 42

# 複数のオブジェクトを保存
with open('multiple.pkl', 'wb') as f:
    pickle.dump(data1, f)
    pickle.dump(data2, f)
    pickle.dump(data3, f)

# 複数のオブジェクトを読み取る(順序は同じである必要があります)
with open('multiple.pkl', 'rb') as f:
    loaded_data1 = pickle.load(f)
    loaded_data2 = pickle.load(f)
    loaded_data3 = pickle.load(f)
   
print(loaded_data1)
print(loaded_data2)
print(loaded_data3)

8. 実用的な応用例

例1:機械学習モデルの設定を保存・読み込み

例

import pickle

# 機械学習モデルの設定をシミュレート
model_config = {
    'model_type': 'RandomForest',
    'n_estimators': 100,
    'max_depth': 10,
    'trained_date': '2024-01-13',
    'accuracy': 0.95
}

# 設定を保存
with open('model_config.pkl', 'wb') as f:
    pickle.dump(model_config, f)

# 設定を読み込み
with open('model_config.pkl', 'rb') as f:
    config = pickle.load(f)
    print(f"モデルタイプ: {config['model_type']}")
    print(f"精度: {config['accuracy']}")

例2:計算結果のキャッシュ

例

import pickle
import os

def expensive_computation(n):
    """時間のかかる計算をシミュレート"""
    result = sum(i ** 2 for i in range(n))
    return result

def compute_with_cache(n, cache_file='cache.pkl'):
    # キャッシュが存在するか確認
    if os.path.exists(cache_file):
        with open(cache_file, 'rb') as f:
            cache = pickle.load(f)
            if n in cache:
                print("キャッシュから結果を読み取ります")
                return cache[n]
    else:
        cache = {}
   
    # 計算を実行
    print("計算を実行しています...")
    result = expensive_computation(n)
   
    # キャッシュに保存
    cache[n] = result
    with open(cache_file, 'wb') as f:
        pickle.dump(cache, f)
   
    return result

# 使用例
print(compute_with_cache(1000000))  # 1回目は計算される
print(compute_with_cache(1000000))  # 2回目はキャッシュから読み取られる

Pickle モジュールの注意点

  1. セキュリティ:pickleモジュールはデシリアライズ時に任意のコードを実行するため、信頼できないソースからのpickleデータを読み込まないでください。悪意のある攻撃を避けるためです。
  2. 互換性:pickle生成されるバイトストリームは Python 固有であり、Python のバージョンが異なると互換性の問題が発生する可能性があります。
  3. パフォーマンス:大規模なデータセットの場合、pickleのシリアライズとデシリアライズは遅くなる可能性があります。より効率的なシリアライズツールの使用を検討できます。例えばjson 或 msgpack。

上級の使い方:カスタムオブジェクトのシリアライズ

pickleモジュールはカスタムクラスのシリアライズをサポートしています。デフォルトでは、pickleオブジェクトの属性とクラス名を保存します。より複雑なシリアライズロジックが必要な場合は、クラス内で実装できます__getstate__()と__setstate__()メソッド。

例

import pickle

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getstate__(self):
        # カスタムシリアライズロジック
        return {'name': self.name, 'age': self.age}

    def __setstate__(self, state):
        # カスタム逆シリアル化ロジック
        self.name = state['name']
        self.age = state['age']

# オブジェクトを作成してシリアル化
person = Person('Bob', 30)
with open('person.pkl', 'wb') as file:
    pickle.dump(person, file)

# オブジェクトを逆シリアル化
with open('person.pkl', 'rb') as file:
    loaded_person = pickle.load(file)

print(loaded_person.name, loaded_person.age)

pickle モジュールのよく使うメソッド

メソッド説明例
pickle.dump(obj, file)オブジェクトをシリアル化してファイルに書き込むpickle.dump(data, open('data.pkl', 'wb'))
pickle.load(file)ファイルから読み込んでオブジェクトを逆シリアル化するdata = pickle.load(open('data.pkl', 'rb'))
pickle.dumps(obj)オブジェクトをバイト列にシリアル化するbytes_data = pickle.dumps([1, 2, 3])
pickle.loads(bytes)バイト列からオブジェクトを逆シリアル化するlst = pickle.loads(bytes_data)
pickle.HIGHEST_PROTOCOL利用可能な最高のプロトコルバージョン(属性)pickle.dump(..., protocol=pickle.HIGHEST_PROTOCOL)
pickle.DEFAULT_PROTOCOLデフォルトのプロトコルバージョン(属性、通常は4)pickle.dumps(obj, protocol=pickle.DEFAULT_PROTOCOL)

1. オブジェクトをファイルにシリアル化

例

import pickle
data = {'name': 'Alice', 'age': 25}
with open('data.pkl', 'wb') as f:
    pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)

2. ファイルから逆シリアル化

例

with open('data.pkl', 'rb') as f:
    loaded_data = pickle.load(f)
print(loaded_data)  # 出力: {'name': 'Alice', 'age': 25}

3. バイト列へのシリアル化(ネットワーク転送/キャッシュ)

例

bytes_data = pickle.dumps([1, 2, 3], protocol=4)
restored_list = pickle.loads(bytes_data)

pickle モジュールのプロトコルバージョン

プロトコルバージョン説明
0人間が読めるASCII形式(旧バージョン互換)
1バイナリ形式(旧バージョン互換)
2Python 2.3+ クラスオブジェクトの最適化サポート
3Python 3.0+ デフォルトプロトコル(Python 2非対応)
4Python 3.4+ より大きなオブジェクトとより多くのデータ型をサポート
5Python 3.8+ メモリ最適化とデータ共有をサポート
その他の拡張