PythonでJSONファイルを整形し出力する方法
Pythonは、その豊富なライブラリと直感的な構文により、JSON(JavaScript Object Notation)ファイルの操作に非常に適しています。JSONは、データ交換フォーマットとして広く利用されており、Web APIとの連携や設定ファイルの管理などで頻繁に登場します。JSONファイルを整形して出力することは、データの可読性を高め、デバッグや解析を容易にするために重要です。
PythonでJSONファイルを整形し、読みやすく出力するには、主に標準ライブラリであるjsonモジュールを使用します。このモジュールは、JSONデータのエンコード(PythonオブジェクトをJSON文字列に変換)およびデコード(JSON文字列をPythonオブジェクトに変換)をサポートしています。
JSONの基本とPythonでの扱い
JSONは、キーと値のペアで構成されるオブジェクト(Pythonの辞書に相当)と、順序付けられた値のリスト(Pythonのリストに相当)から成り立っています。Pythonでは、これらの構造がdict型とlist型として自然にマッピングされます。
JSONデータの読み込み
JSONファイルをPythonプログラムで扱う最初のステップは、ファイルからJSONデータを読み込むことです。jsonモジュールのload()関数またはloads()関数を使用します。load()関数はファイルオブジェクトから直接JSONデータを読み込み、loads()関数はJSON文字列からデータを読み込みます。
import json
# ファイルからJSONデータを読み込む場合
with open('input.json', 'r', encoding='utf-8') as f:
data = json.load(f)
# JSON文字列からデータを読み込む場合
json_string = '{"name": "Alice", "age": 30, "isStudent": false}'
data = json.loads(json_string)
ここで、input.jsonは、整形したいJSONデータが含まれるファイル名とします。encoding='utf-8'を指定することで、日本語などのマルチバイト文字も正しく扱えます。
JSONデータの整形と出力
JSONデータを整形して出力する際には、jsonモジュールのdump()関数またはdumps()関数が利用されます。これらの関数は、PythonオブジェクトをJSON形式の文字列に変換します。整形のための主要な引数は、indentとsort_keysです。
import json
# サンプルJSONデータ
data = {
"name": "Bob",
"age": 25,
"courses": [
{"title": "Math", "credits": 3},
{"title": "Science", "credits": 4}
],
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
# 整形して標準出力に表示する場合
print(json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False))
# 整形してファイルに出力する場合
with open('output.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4, sort_keys=True, ensure_ascii=False)
indent引数
indent引数は、JSONのネスト構造を視覚的に分かりやすくするために、インデント(字下げ)のスペース数を指定します。例えば、indent=4と指定すると、各ネストレベルで4つのスペースが挿入されます。これにより、JSONデータはツリー構造のように表示され、どのキーがどの値に対応しているかが一目瞭然になります。
indent=None(デフォルト)の場合、JSONデータは1行に圧縮されて出力され、可読性は低くなります。
sort_keys引数
sort_keys=Trueと指定すると、JSONオブジェクト内のキーがアルファベット順にソートされて出力されます。これは、特に同じ構造を持つ複数のJSONファイルを比較する際に役立ちます。キーの順序が一定になるため、差分検出などが容易になります。
デフォルトはFalseであり、キーの順序はPythonの辞書に格納された順序(Python 3.7以降)または挿入順序に従います。
ensure_ascii引数
ensure_ascii=Falseと指定することは、非ASCII文字(日本語など)をそのまま出力するために重要です。デフォルトではTrueになっており、非ASCII文字はuXXXXのようなエスケープシーケンスに変換されてしまいます。日本語などの文字化けを防ぐために、ensure_ascii=Falseを指定し、encoding='utf-8'を併用することが推奨されます。
その他の整形オプションと考慮事項
separators引数
separators引数は、キーと値の間の区切り文字(:)や、要素間の区切り文字(,)をカスタマイズするために使用できます。一般的には、整形時にはデフォルトのままで問題ありませんが、JSONを最小限のサイズで出力したい場合に、スペースを削除するために使用されることがあります。
# スペースなしで出力する場合
print(json.dumps(data, separators=(',', ':')))
default引数
default引数は、JSONにシリアライズできないカスタムオブジェクト(例:datetimeオブジェクト)を処理するために使用できます。この引数に、カスタムオブジェクトをJSONで表現可能な形式(文字列など)に変換する関数を指定します。
import datetime
def json_serial(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
raise TypeError(f"Type {type(obj)} not serializable")
now = datetime.datetime.now()
data_with_date = {"timestamp": now}
print(json.dumps(data_with_date, indent=4, default=json_serial, ensure_ascii=False))
パフォーマンスに関する考慮事項
非常に大きなJSONファイルを扱う場合、json.load()やjson.dump()はメモリを大量に消費する可能性があります。そのような場合は、ストリーミングAPIやイテレータベースのJSONパーサー(例:ijsonライブラリ)の利用を検討すると良いでしょう。
エラーハンドリング
JSONファイルの読み込みや解析中にエラーが発生する可能性も考慮する必要があります。try-exceptブロックを使用して、json.JSONDecodeErrorなどの例外を捕捉し、適切に処理することが重要です。
try:
with open('malformed.json', 'r', encoding='utf-8') as f:
data = json.load(f)
except json.JSONDecodeError as e:
print(f"JSONデコードエラー: {e}")
except FileNotFoundError:
print("ファイルが見つかりませんでした。")
まとめ
Pythonのjsonモジュールは、JSONデータの整形と出力において強力な機能を提供します。json.dumps()関数(またはjson.dump()関数)のindent、sort_keys、ensure_asciiといった引数を適切に活用することで、可読性の高いJSON出力を実現できます。これらの機能を理解し、状況に応じて使い分けることで、JSONデータの取り扱いが格段に容易になります。
