PythonとJSON:完全ガイド
PythonでJSONを扱う方法を学びます。読み取り、書き込み、パース、シリアライズ、エラー処理、ベストプラクティス。
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# PythonとJSON:完全ガイド
Pythonには強力な組み込みJSONサポートがあり、JSONデータの操作が簡単です。
jsonモジュール
Pythonのjsonモジュールは、JSONデータを扱うための標準ライブラリです。
インポート
import json
JSONの読み取り
文字列からのパース
import json
# JSON文字列
json_string = '{"name": "田中太郎", "age": 30, "city": "東京"}'
# Pythonオブジェクトに変換
data = json.loads(json_string)
print(data['name']) # 田中太郎
print(data['age']) # 30
print(type(data)) # <class 'dict'>
ファイルからの読み取り
import json
# JSONファイルを読み取り
with open('data.json', 'r', encoding='utf-8') as file:
data = json.load(file)
print(data)
例:user.json
{
"name": "田中太郎",
"age": 30,
"email": "tanaka@example.com",
"hobbies": ["読書", "旅行", "料理"]
}
with open('user.json', 'r', encoding='utf-8') as f:
user = json.load(f)
print(f"名前: {user['name']}")
print(f"趣味: {', '.join(user['hobbies'])}")
JSONの書き込み
オブジェクトから文字列へ
import json
# Python辞書
user = {
"name": "田中太郎",
"age": 30,
"city": "東京",
"active": True,
"balance": None
}
# JSON文字列に変換
json_string = json.dumps(user, ensure_ascii=False)
print(json_string)
# {"name": "田中太郎", "age": 30, "city": "東京", "active": true, "balance": null}
フォーマットされた出力
# インデント付き
json_string = json.dumps(user, indent=2, ensure_ascii=False)
print(json_string)
# {
# "name": "田中太郎",
# "age": 30,
# "city": "東京",
# "active": true,
# "balance": null
# }
ファイルへの書き込み
import json
user = {
"name": "田中太郎",
"age": 30,
"email": "tanaka@example.com"
}
# ファイルに書き込み
with open('output.json', 'w', encoding='utf-8') as f:
json.dump(user, f, indent=2, ensure_ascii=False)
データ型マッピング
Python → JSON
| Python | JSON |
|--------|------|
| dict | object |
| list, tuple | array |
| str | string |
| int, float | number |
| True | true |
| False | false |
| None | null |
JSON → Python
| JSON | Python |
|------|--------|
| object | dict |
| array | list |
| string | str |
| number (int) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
例
import json
# Pythonデータ
data = {
"string": "こんにちは",
"number": 42,
"float": 3.14,
"boolean": True,
"null_value": None,
"list": [1, 2, 3],
"nested": {
"key": "value"
}
}
# JSON変換
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
# 逆変換
parsed = json.loads(json_str)
print(type(parsed['boolean'])) # <class 'bool'>
詳細設定
ensure_ascii
# ensure_ascii=True(デフォルト)
json.dumps({"name": "田中"})
# '{"name": "\u7530\u4e2d"}'
# ensure_ascii=False
json.dumps({"name": "田中"}, ensure_ascii=False)
# '{"name": "田中"}'
sort_keys
data = {"c": 3, "a": 1, "b": 2}
# キーをソート
json.dumps(data, sort_keys=True)
# '{"a": 1, "b": 2, "c": 3}'
indent
data = {"name": "田中", "age": 30}
# インデント2
print(json.dumps(data, indent=2, ensure_ascii=False))
# {
# "name": "田中",
# "age": 30
# }
# インデント4
print(json.dumps(data, indent=4, ensure_ascii=False))
separators
# コンパクト出力
json.dumps(data, separators=(',', ':'))
# '{"name":"田中","age":30}'
# 読みやすい出力
json.dumps(data, separators=(', ', ': '))
# '{"name": "田中", "age": 30}'
カスタムエンコーディング
カスタムクラスのシリアライズ
import json
from datetime import datetime
class User:
def __init__(self, name, age, created):
self.name = name
self.age = age
self.created = created
# カスタムエンコーダー
class UserEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, User):
return {
'name': obj.name,
'age': obj.age,
'created': obj.created.isoformat()
}
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
# 使用
user = User("田中太郎", 30, datetime.now())
json_str = json.dumps(user, cls=UserEncoder, ensure_ascii=False)
print(json_str)
default関数を使用
from datetime import datetime
def json_serial(obj):
"""JSON serializer for objects not serializable by default"""
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Type {type(obj)} not serializable")
data = {
"name": "田中太郎",
"created": datetime.now()
}
json_str = json.dumps(data, default=json_serial, ensure_ascii=False)
カスタムデコーディング
object_hook
import json
from datetime import datetime
def decode_user(dct):
if 'created' in dct:
dct['created'] = datetime.fromisoformat(dct['created'])
return dct
json_str = '{"name": "田中太郎", "created": "2026-01-16T10:00:00"}'
data = json.loads(json_str, object_hook=decode_user)
print(type(data['created'])) # <class 'datetime.datetime'>
エラー処理
JSONDecodeError
import json
invalid_json = '{"name": "田中太郎", "age": 30,}' # 末尾のカンマ
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"JSONエラー: {e.msg}")
print(f"行: {e.lineno}, 列: {e.colno}")
print(f"位置: {e.pos}")
安全なパース
def safe_json_loads(json_str, default=None):
"""安全にJSONをパース"""
try:
return json.loads(json_str)
except json.JSONDecodeError as e:
print(f"JSONパースエラー: {e}")
return default
except Exception as e:
print(f"予期しないエラー: {e}")
return default
# 使用
result = safe_json_loads('invalid json', default={})
大きなJSONファイル
ストリーミング読み取り
import json
# 大きなファイルの場合
with open('large.json', 'r', encoding='utf-8') as f:
# 一度にすべて読み込む代わりに
for line in f:
try:
data = json.loads(line)
# 各行を処理
process_data(data)
except json.JSONDecodeError:
continue
ijsonを使用(ストリーミング)
import ijson
# 大きなJSONファイルをストリーミング
with open('large.json', 'rb') as f:
objects = ijson.items(f, 'item')
for obj in objects:
# 各アイテムを処理
print(obj)
実用例
API リクエスト
import json
import requests
# APIからデータを取得
response = requests.get('https://api.example.com/users')
users = response.json()
# または
users = json.loads(response.text)
for user in users:
print(f"{user['name']}: {user['email']}")
設定ファイル
import json
# config.json
config = {
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb"
},
"api_key": "secret123",
"debug": True
}
# 設定を保存
with open('config.json', 'w') as f:
json.dump(config, f, indent=2)
# 設定を読み込み
with open('config.json', 'r') as f:
config = json.load(f)
db_host = config['database']['host']
データ変換
import json
import csv
# CSVをJSONに変換
def csv_to_json(csv_file, json_file):
data = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
data.append(row)
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
csv_to_json('users.csv', 'users.json')
ネストされたデータへのアクセス
import json
data = {
"users": [
{
"name": "田中太郎",
"address": {
"city": "東京",
"zip": "100-0001"
}
}
]
}
# 安全なアクセス
def get_nested(data, *keys, default=None):
"""ネストされた辞書から値を安全に取得"""
for key in keys:
try:
data = data[key]
except (KeyError, TypeError, IndexError):
return default
return data
# 使用
city = get_nested(data, 'users', 0, 'address', 'city')
print(city) # 東京
missing = get_nested(data, 'users', 0, 'phone', default='N/A')
print(missing) # N/A
JSON Schema検証
import json
from jsonschema import validate, ValidationError
# スキーマ定義
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number", "minimum": 0},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "email"]
}
# データ検証
data = {
"name": "田中太郎",
"age": 30,
"email": "tanaka@example.com"
}
try:
validate(instance=data, schema=schema)
print("データは有効です")
except ValidationError as e:
print(f"検証エラー: {e.message}")
ベストプラクティス
1. 常にencoding指定
# 良い
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
# 悪い(システム依存)
with open('data.json', 'r') as f:
data = json.load(f)
2. ensure_ascii=Falseを使用(日本語の場合)
# 読みやすい
json.dumps(data, ensure_ascii=False)
# 読みにくい
json.dumps(data) # \u エスケープ
3. エラーハンドリング
try:
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
except FileNotFoundError:
print("ファイルが見つかりません")
except json.JSONDecodeError:
print("無効なJSON")
except Exception as e:
print(f"エラー: {e}")
4. コンテキストマネージャを使用
# 良い
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f)
# 悪い(ファイルが閉じられない可能性)
f = open('data.json', 'w')
json.dump(data, f)
f.close()
よくある落とし穴
1. タプルはリストになる
data = {"coords": (10, 20)}
json_str = json.dumps(data)
parsed = json.loads(json_str)
print(type(parsed['coords'])) # <class 'list'>, not tuple
2. 辞書のキーは文字列のみ
data = {1: "one", 2: "two"}
json_str = json.dumps(data)
parsed = json.loads(json_str)
print(parsed) # {"1": "one", "2": "two"}
3. 循環参照
data = {"name": "田中"}
data["self"] = data # 循環参照
# エラー
json.dumps(data) # ValueError: Circular reference detected
まとめ
クイックリファレンス
import json
# 読み取り
data = json.loads(json_string) # 文字列から
data = json.load(file) # ファイルから
# 書き込み
json_string = json.dumps(data) # 文字列へ
json.dump(data, file) # ファイルへ
# オプション
json.dumps(data,
indent=2, # フォーマット
ensure_ascii=False, # 日本語そのまま
sort_keys=True # キーをソート
)
よく使うパターン
# 美しいJSON出力
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# 安全な読み取り
try:
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"エラー: {e}")
data = {}
PythonのJSONサポートで、データ処理を簡単に!