Python標準ライブラリでデータ保存とシリアライズ:jsonpicklecsv

データをファイルに保存したりネットワークで送受信したりするには、シリアライズ(Serialization)が必要です。 Pythonは、用途に応じて3つの標準ツールを提供しています:jsonpicklecsv

データ配送フォーマット業者

  • json:人間が読めるテキストフォーマットで、言語間のデータ交換に適している
  • pickle:Pythonオブジェクトをそのまま保存するバイナリフォーマットで、強力な一方リスクも伴う
  • csv:表(テーブル)データを最もシンプルに格納できるテキストフォーマットで、汎用性が高い

この記事では「どのデータをどこで使うか」に応じて、3つのモジュールを選ぶ基準を整理します。


1. JSON

1.1 概要

JSON(JavaScript Object Notation)はテキストベース言語に依存しません。 設定ファイル、APIのレスポンス/リクエスト、ログなど、他のシステムとデータ交換しやすい形式として広く使われます。Pythonではjsonモジュールで直接扱えます。

1.2 コアAPI(よく使うものだけ)

  • json.dump(obj, fp, ...) / json.load(fp, ...):ファイルへの保存/読み込み
  • json.dumps(obj, ...) / json.loads(s, ...):文字列への変換/復元

覚えておくと便利なオプション:

  • ensure_ascii=False:ASCII以外の国際文字(例:ラテン拡張、キリル、CJKなど)をエスケープせずにそのまま保存/出力
  • indent=2:見やすく整形
  • default=...:JSONが対応していない型を変換する「回避策」

1.3 使用例(基本)

import json

data = {
    "name": "Alice",
    "age": 30,
    "skills": ["Python", "Data Science"]
}

with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded)

1.4 JSONの「型制限」を簡単に解決する方法

JSONは基本的にdictliststrint/floatboolNoneのみをそのまま扱えます。 例えばdatetimeはそのまま保存できません。このような場合にdefaultを使うと、簡潔に解決できます。

defaultには変換関数(callable)を渡します。jsonがシリアライズできないオブジェクトに出会うと、そのオブジェクトが関数の引数に渡され、関数はstr/dict/listなどJSONが解釈可能な型に変換して返します。

import json
from datetime import datetime, timezone

payload = {"created_at": datetime.now(timezone.utc)}

def to_jsonable(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Not JSON serializable: {type(obj)!r}")

s = json.dumps(payload, default=to_jsonable, ensure_ascii=False)
print(s)

1.5 長所と短所

長所

  • 言語に依存せず、データ交換・共有に適している
  • テキストなのでデバッグしやすく、Gitなどのバージョン管理にも適している
  • pickleのように、ロードするだけでコードが実行されるような構造ではない

短所

  • 型表現力が限定的(特にdatetimesetDecimal、バイナリデータなど)
  • 大量データでは容量・速度面で劣ることがある

2. Pickle

2.1 概要

picklePythonオブジェクトを「Pythonの形式を保ったまま」保存するシリアライズ方式です。結果は人間が読めるテキストではなくバイナリデータ(bytes)で、再読み込みすると、ほぼ同一のオブジェクトとして復元されます。

pickleが特に有用なケースは次のとおりです。

  • 複雑なPythonオブジェクトをそのまま保存したいとき 例:ユーザー定義クラスのインスタンス、入れ子構造、学習済みモデル/設定オブジェクト(Pythonオブジェクト形式)、計算結果のキャッシュなど
  • 他言語との交換が不要なとき pickleはPython専用フォーマットなので、共有/交換目的なら通常はjsonの方が適しています。

逆に、次の状況では避ける方が良いです。

  • 信頼できない出所のデータを読み込むときpickle.load()は危険)
  • 他言語や他システムとデータをやり取りするとき(互換性がない)

2.2 コアAPI(最も使われる4つ)

  • pickle.dump(obj, file, protocol=...):オブジェクトをファイル(バイナリ)へ保存
  • pickle.load(file):ファイルから読み込み、オブジェクトへ復元
  • pickle.dumps(obj, protocol=...):オブジェクトをbytesへ変換
  • pickle.loads(data):bytesからオブジェクトへ復元

以下に示すように、ファイルへの保存や読み込みが最も一般的な利用方法です。

import pickle

data = {"a": [1, 2, 3], "b": ("x", "y")}

with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

with open("data.pkl", "rb") as f:
    loaded = pickle.load(f)

print(loaded)

2.3 protocolとは何か、そしてなぜ気にするのか

protocolpickleがデータを保存する際の「フォーマットバージョン」です。 プロトコルバージョンによってファイルサイズ、処理速度、サポートされる機能が異なります。

  • protocol指定しない場合:Pythonが現在の環境で最適なデフォルトプロトコルを使用します。
  • 通常はデフォルトのままで十分です。
  • 変更が必要になるケースは主に以下の2つです: 1. 非常に古いPythonバージョンとの互換性を確保するために、低いプロトコルを強制する場合 2. ファイルサイズや速度を最適化するために、明示的に最新のプロトコルを指定したい場合

よく使われるパターンは「最新プロトコル」を指定することです。

import pickle

with open("data.pkl", "wb") as f:
    pickle.dump({"x": 1}, f, protocol=pickle.HIGHEST_PROTOCOL)

まとめ:最初はprotocolについて意識する必要はありません。必要になった際にpickle.HIGHEST_PROTOCOLを思い出せば問題ありません。


2.4 pickleの本当の注意点(重要)

pickle.load() / pickle.loads()データ内に含まれる「復元ロジック」を実行します。 つまり、信頼できないpickleデータをロードすると意図しない動作が発生する可能性があります。

  • 安全な選択:「出所が不明な.pklファイルは開かない」
  • 共有や交換目的なら:jsonのようなテキストベースのフォーマットをデフォルトとして使用する

2.5 長所と短所

長所

  • Pythonオブジェクトを広範囲に保存可能(ほぼあらゆるオブジェクトに対応)
  • 通常jsonより高速で便利(特に複雑なオブジェクト)

短所

  • セキュリティリスク(信頼できないデータは絶対にロードしない)
  • Python専用(他言語と互換性がない)
  • クラス定義が変わると過去のpickleが壊れる可能性(バージョン互換性の問題)

3. CSV

3.1 概要

CSV(Comma-Separated Values)は表形式データを格納するための最も単純なフォーマットです。 スプレッドシート、データのエクスポート/インポート、簡易ログダンプなどで頻繁に利用されます。

3.2 コアAPI(よく使うものだけ)

  • csv.readercsv.writer:リストを扱う
  • csv.DictReadercsv.DictWriter:辞書を扱う(多くの場合、こちらの方が便利)

3.3 使用例(DictWriter/DictReader)

import csv

data = [
    {"name": "Alice", "age": 30, "city": "Seoul"},
    {"name": "Bob",   "age": 25, "city": "Busan"},
]

with open("people.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age", "city"])
    writer.writeheader()
    writer.writerows(data)

with open("people.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    loaded = list(reader)

print(loaded)

3.4 CSV利用時の3つの注意点

  1. newline=""を必ず指定 * 特にWindows環境で、行末が二重になる問題を避けるために推奨されます
  2. 型は基本的にすべて文字列 * 読み込み時には"30"のように文字列として扱われる。必要な列は手動で型変換を行う必要があります
  3. 区切り文字/引用符/改行がデータに含まれる可能性 * CSVは単純に見えますが、「値にカンマが含まれる場合」など、特定のルールが存在します。csvモジュールを使用することで安全に処理できます

3.5 長所と短所

長所

  • 非常に軽量で汎用的(ほとんどのツールが読み書き可能)
  • 表データに対しては非常にシンプルで扱いやすい

短所

  • ネスト構造(リスト内のリスト、辞書の入れ子など)は表現が難しい
  • 型情報がないため変換コストがかかる

4. 比較 & 選択ガイド

項目 JSON Pickle CSV
他言語との互換性 非常に良い Python専用 非常に良い
可読性 高い 低い(バイナリ) 高い
型表現力 制限的 非常に高い 制限的
安全性 比較的安全 注意が必要 比較的安全
データ形式 木構造(ネスト) Pythonオブジェクトそのまま テーブル(行/列)

一文でまとめると:

  • 他システムとやり取りするjson
  • Pythonオブジェクトを丸ごと保存するpickle(ただしロード元の信頼性を厳密に確認する)
  • 行/列形式で出力・読み込みcsv

5. 同じデータを3種類で保存/復元する

以下は同じデータをjsonpicklecsvでそれぞれ保存し、再度読み込む例です。

import json, pickle, csv

data = [
    {"id": 1, "name": "Alice", "score": 95.5},
    {"id": 2, "name": "Bob",   "score": 88.0},
]

# 1) JSON
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    json_loaded = json.load(f)

# 2) Pickle
with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

with open("data.pkl", "rb") as f:
    pickle_loaded = pickle.load(f)

# 3) CSV
with open("data.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["id", "name", "score"])
    writer.writeheader()
    writer.writerows(data)

with open("data.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    csv_loaded = [
        {"id": int(row["id"]), "name": row["name"], "score": float(row["score"])}
        for row in reader
    ]

print(json_loaded)
print(pickle_loaded)
print(csv_loaded)

ポイント:

  • CSVは読み込み時に数値変換を行わないと、「意図した型」として扱えない
  • pickleは便利だが、ロードデータの出所を慎重に管理する必要がある

6. まとめ

Python標準ライブラリだけで、データ保存とシリアライズに関して驚くほど広い範囲をカバーできます。

  • 人も読め、他言語も読めるjson
  • Pythonオブジェクトをそのまま保管したいpickle
  • 表形式で簡単に出力したいcsv

この3つのモジュールの中で、保存したいデータの形状と目的に合わせて選べば、適切なモジュールを迅速かつ明確に選択できます。