JSON(JavaScript Object Notation)は、Web API や設定ファイル、データ交換の標準フォーマットとして広く採用されています。Python は標準ライブラリ json を通じて、文字列やファイルからの JSON データのデシリアライズをネイティブにサポートしており、型安全性やエラー処理を意識した使い方が可能です。
基本的なパースフロー
JSON を Python のネイティブオブジェクト(dict、list、str、int、float、bool、None)に変換するには、以下のパターンが主です:
json.loads():JSON 形式の文字列からオブジェクトへjson.load():ファイルオブジェクト(テキストモード)から直接読み込み
安全な文字列パース例(バリデーション付き)
不正な JSON 入力への耐性を持つため、例外処理と型検証を組み合わせます:
import json
from typing import Dict, List, Optional, Any
def parse_person_json(raw: str) -> Optional[Dict[str, Any]]:
try:
payload = json.loads(raw)
# 基本フィールドの存在確認
if not isinstance(payload, dict):
raise ValueError("root must be a JSON object")
if "full_name" not in payload or "years" not in payload:
raise ValueError("required keys 'full_name' and 'years' missing")
if not isinstance(payload["years"], (int, float)) or payload["years"] < 0:
raise ValueError("invalid 'years' value")
return payload
except json.JSONDecodeError as e:
print(f"JSON syntax error at position {e.pos}: {e.msg}")
return None
except ValueError as e:
print(f"Data validation failed: {e}")
return None
# 使用例
sample = '{"full_name": "Yuki Tanaka", "years": 29, "tags": ["backend", "devops"]}'
parsed = parse_person_json(sample)
if parsed:
print(f"Person: {parsed['full_name']}, Age: {parsed['years']}")
ファイルからのロードと構造化アクセス
JSON ファイルを読み込む際は、エンコーディング指定とコンテキストマネージャーを活用し、リソースリークを防ぎます:
import json
from pathlib import Path
def load_config(path: Path) -> dict:
try:
with path.open("r", encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
raise RuntimeError(f"Config file not found: {path}")
except UnicodeDecodeError as e:
raise RuntimeError(f"Invalid encoding in {path}: {e}")
except json.JSONDecodeError as e:
raise RuntimeError(f"Malformed JSON in {path} at line {e.lineno}")
# 設定ファイル config.json の想定内容:
# {"database": {"host": "localhost", "port": 5432}, "debug": true}
config = load_config(Path("config.json"))
db_host = config.get("database", {}).get("host", "127.0.0.1")
is_debug = config.get("debug", False)
print(f"DB Host: {db_host}, Debug Mode: {is_debug}")
ネストされた配列と動的キーの扱い
複雑な構造でも、.get() とデフォルト値を活用することで安全にアクセスできます:
api_response = '''
{
"status": "success",
"items": [
{"id": 101, "meta": {"category": "web", "score": 92.5}},
{"id": 102, "meta": {"category": "mobile", "score": 87.3}}
]
}
'''
data = json.loads(api_response)
for item in data.get("items", []):
meta = item.get("meta", {})
category = meta.get("category", "unknown")
rating = round(meta.get("score", 0.0))
print(f"ID {item.get('id', '?')} → {category.upper()}: {rating}/100")