PythonでJSONファイルを整形し出力する方法

プログラミング

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形式の文字列に変換します。整形のための主要な引数は、indentsort_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()関数)のindentsort_keysensure_asciiといった引数を適切に活用することで、可読性の高いJSON出力を実現できます。これらの機能を理解し、状況に応じて使い分けることで、JSONデータの取り扱いが格段に容易になります。