JSONとPythonは同じ"形"を共有している
JSONはAPI、設定ファイル、そしてWeb上のデータ交換において事実上の標準フォーマットです。Pythonを書く人にとってありがたいのは、JSONのオブジェクトがPythonのdictに、JSONの配列がlistに、JSONの文字列がstrにそのまま対応していること。この構造のきれいな一致があるからこそ、PythonでJSONを読み書きするのはほぼ2行で済んでしまいます。
標準ライブラリのjsonモジュールが、読み込みと書き出しの両方を担当します。
JSON文字列をパースする
json.loads(text) — 「load string(文字列から読み込む)」の略で、JSON形式の文字列を受け取って、対応するPythonオブジェクトを返してくれます。
返ってくるのは普通の dict です。JSON 専用のラッパーや .parse() のようなメソッドはなく、通常の辞書と同じ感覚でキーにアクセスできます。
文字列が不正な JSON だった場合は、json.loads が json.JSONDecodeError を送出します。エラーメッセージには問題が起きた行番号と列番号が含まれるので、カンマ漏れやエスケープされていないクォートを特定するのにたいてい十分です。
Python オブジェクトを JSON 文字列に変換する
json.dumps(data)(「dump string」の略)は逆方向の処理で、Python オブジェクトを受け取って JSON 文字列を返します。
Pythonの True、False、None は、JSONでは自動的に true、false、null に変換されます。数値や文字列はそのまま、リストは配列、辞書はオブジェクトになります。
JSONを整形して見やすく出力する
json.dumps のデフォルト出力はコンパクトで、ネットワーク転送には向いていますが、人間が読むにはつらいですよね。そんなときは indent=2 を指定すると、ぐっと読みやすくなります。
dumps で覚えておきたいオプションを、ほかにもいくつか紹介します。
sort_keys=True— オブジェクトのキーをアルファベット順に並べます。出力を安定させたいとき(設定ファイル、テストのフィクスチャ、差分比較など)に便利です。ensure_ascii=False— 非ASCII文字(é、ü、中、あ など)を\uエスケープではなくそのまま出力します。UTF-8 ファイルに書くならほぼこれ一択です。separators=(",", ":")— 可能な限りコンパクトな出力にします。ensure_ascii=Falseと組み合わせれば、UTF-8 JSON を最小サイズで書き出せます。
JSON ファイルを読み込む
json.load(file) は(末尾に s が付かないことに注意)、ファイルオブジェクトから直接読み込みます。定番の書き方は with open との組み合わせです。
import json
with open("config.json") as f:
config = json.load(f)
print(config["version"])
ファイル全体を一度文字列として読み込む必要はありません。json.load はファイルオブジェクトを直接ストリームで処理してくれます。
JSON をファイルに書き込む
ファイルへの書き込みには、対になる json.dump(data, file) を使います。
import json
data = {"created": "2026-01-01", "items": [1, 2, 3]}
with open("state.json", "w") as f:
json.dump(data, f, indent=2)
indent オプションはこちらでも使えます。出力されたファイルを開くと、きれいに整形された JSON ドキュメントが確認できるはずです。
JSON APIのレスポンスをパースする
多くのHTTPライブラリはバイト列や文字列を返してくるので、json.loads で扱いやすいデータ構造に変換します。
import json
import urllib.request
with urllib.request.urlopen("https://api.example.com/users/1") as response:
text = response.read().decode("utf-8")
user = json.loads(text)
print(user["name"])
requestsライブラリ(こちらは別途解説します)を使えば一手間省けます。レスポンスに.json()メソッドが生えていて、内部でjson.loadsを呼んでくれるんです。
JSONで表現できるもの・できないもの
JSONの型システムはPythonに比べると表現力が狭めです。両方向の対応関係を整理するとこうなります。
| Python | JSON |
|---|---|
dict | object |
list, tuple | array |
str | string |
int, float | number |
True | true |
False | false |
None | null |
タプルはリストとして往復します。つまり、シリアライズして戻すとタプルだったという情報は失われるわけです。また、setや自作クラス、datetimeオブジェクトはデフォルトではシリアライズできず、TypeError: Object of type X is not JSON serializableというエラーが出ます。
datetimeや自作クラスを扱う
よく使うアプローチは2つあります。
まずJSONで扱える形に変換しておく方法。 自分のコード側で整形してから、素のdictをシリアライズします。
default= に関数を渡す方法。json.dumps はシリアライズできない値に出会うたびに、この関数を呼び出してくれます。
データを読み込む側では、ISO形式の文字列を自分でdatetimeに戻してあげる必要があります。JSONは元の型が何だったかまでは覚えていないからです。
dictをJSONで往復させてみる
dictがちゃんと往復できるか、サッと確認してみましょう。
値としては等しいものの、オブジェクトとしては別物です。これはむしろ便利な性質で、json.dumps と json.loads を組み合わせれば、JSON 互換のデータ構造を手軽にディープコピーできます。
実践的なサンプル
JSON の設定ファイルを読み込んで、値を書き換え、また保存し直す小さなスクリプトを見てみましょう。
import json
from pathlib import Path
config_path = Path("settings.json")
# Load (with a default if the file doesn't exist).
if config_path.exists():
config = json.loads(config_path.read_text())
else:
config = {"theme": "dark", "last_opened": None}
# Update.
config["last_opened"] = "2026-01-15"
# Save, pretty-printed.
config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False))
「読み込み → 加工 → 書き込み」というJSONの一連の流れが、たった十数行で書けてしまいます。
押さえておきたいポイント
- ファイル操作は必ず
with open(...)を使う。JSONは結局ただのテキストなので、通常のファイル処理のルールがそのまま当てはまります。 - 人間が読むファイルは
indent=2で整形するのがおすすめです。設定ファイルやフィクスチャ、エクスポートデータなどが該当します。通信用途ではサイズ優先なので、整形は不要です。 - UTF-8で出力するなら
ensure_ascii=Falseを指定しましょう。アクセント付き文字や日本語などの非ASCII文字がそのまま読める形で保存されます。 - 自分で作っていないデータをパースするときは
try/except json.JSONDecodeErrorで検証しておくと安心です。
次のステップ
JSONはキーと値で構成されたデータを扱うのに向いています。同じ章で次に登場するのはCSV。スプレッドシートからエクスポートされるデータでおなじみの表形式フォーマットで、Pythonには標準ライブラリで対応するモジュールが用意されています。
よくある質問
PythonでJSONをパースするには?
文字列なら json.loads(text)、ファイルオブジェクトなら json.load(file) を使います。どちらも返り値はPythonのdict(JSONの中身によってはlist)です。例えば data = json.loads('{"name": "Rosa"}') とすれば、data['name'] で 'Rosa' が取れます。
PythonのdictをJSONに変換するには?
json.dumps(my_dict) でJSON文字列が返ります。ファイルに直接書き出したいときは json.dump(my_dict, file) です。indent=2 を渡せばきれいに整形された形で出力できます: json.dumps(data, indent=2)。
json.loadsとjson.loadの違いは?
loads(末尾に s あり)は文字列を受け取り、load(s なし)はファイルオブジェクトを受け取ります。dumps と dump も同じルールです。s は string の s と覚えておけば迷いません。
日付やカスタムオブジェクトはどう扱えばいい?
JSONには日付型がないので、ISO-8601形式の文字列として渡し、読み込むときに自分でパースし直すのが定石です。自作クラスの場合は、json.dumps の default= にJSON化可能な形へ変換する関数を渡すか、シリアライズ前に自分で dict に変換してしまうのが手っ取り早いです。