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

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は基本的にdict、list、str、int/float、bool、Noneのみをそのまま扱えます。
例えば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のように、ロードするだけでコードが実行されるような構造ではない
短所
- 型表現力が限定的(特に
datetime、set、Decimal、バイナリデータなど) - 大量データでは容量・速度面で劣ることがある
2. Pickle
2.1 概要
pickleはPythonオブジェクトを「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とは何か、そしてなぜ気にするのか
protocolはpickleがデータを保存する際の「フォーマットバージョン」です。
プロトコルバージョンによってファイルサイズ、処理速度、サポートされる機能が異なります。
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.reader、csv.writer:リストを扱うcsv.DictReader、csv.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つの注意点
newline=""を必ず指定 * 特にWindows環境で、行末が二重になる問題を避けるために推奨されます- 型は基本的にすべて文字列
* 読み込み時には
"30"のように文字列として扱われる。必要な列は手動で型変換を行う必要があります - 区切り文字/引用符/改行がデータに含まれる可能性
* CSVは単純に見えますが、「値にカンマが含まれる場合」など、特定のルールが存在します。
csvモジュールを使用することで安全に処理できます
3.5 長所と短所
長所
- 非常に軽量で汎用的(ほとんどのツールが読み書き可能)
- 表データに対しては非常にシンプルで扱いやすい
短所
- ネスト構造(リスト内のリスト、辞書の入れ子など)は表現が難しい
- 型情報がないため変換コストがかかる
4. 比較 & 選択ガイド
| 項目 | JSON | Pickle | CSV |
|---|---|---|---|
| 他言語との互換性 | 非常に良い | Python専用 | 非常に良い |
| 可読性 | 高い | 低い(バイナリ) | 高い |
| 型表現力 | 制限的 | 非常に高い | 制限的 |
| 安全性 | 比較的安全 | 注意が必要 | 比較的安全 |
| データ形式 | 木構造(ネスト) | Pythonオブジェクトそのまま | テーブル(行/列) |
一文でまとめると:
- 他システムとやり取りする →
json - Pythonオブジェクトを丸ごと保存する →
pickle(ただしロード元の信頼性を厳密に確認する) - 行/列形式で出力・読み込み →
csv
5. 同じデータを3種類で保存/復元する
以下は同じデータをjson、pickle、csvでそれぞれ保存し、再度読み込む例です。
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つのモジュールの中で、保存したいデータの形状と目的に合わせて選べば、適切なモジュールを迅速かつ明確に選択できます。