cloverrose's blog

Python, Machine learning, Emacs, CI/CD, Webアプリなど

Pythonのjsonモジュールの便利機能

PythonJSONを読み書きする機会が割りとあったんですが、改めて調べたり、公式ドキュメントをちゃんと読んだら便利な機能を知ったのでメモしておきます。

jsonファイルの辞書を順番通りにloadしたい

設定ファイルとしてJSONを使っている時、普通にloadすると辞書の順番は保たれません。 でも、プログラム内部で設定を書き足してdumpするような場合、人間が書いた部分がごちゃごちゃになるとよろしくありません。

Pythonjsonモジュールでは次のようにすると順番通りに読み込めます。

import json
import collections


decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
with open('conf.json') as conf_file:
    conf = decoder.decode(conf_file.read())

参考

最初に見つけた回答 Can I get JSON to load into an OrderedDict in Python? - Stack Overflow

公式ドキュメントでは以下のように書いてあります。

object_pairs_hook はオプションで渡す関数で、ペアの順序付きリストのデコード結果に対して呼ばれます。 object_pairs_hook の返り値は dict の代わりに使われます。この機能はキーと値のデコードされる順序に依存する独自のデコーダ (たとえば collections.OrderedDict() は挿入の順序を記憶します) を実装するのに使えます。 object_hook も定義されている場合は、 object_pairs_hook が優先して使用されます。

バージョン 2.7 で変更: object_pairs_hook のサポートを追加しました。

jsonをdumpするときにの行末空白(trailing whitespace)を無くしたい

出力するJSONが人が見る設定ファイルの場合、適切に改行やインデントを設定すると思います。 しかし、indentを設定すると行末空白が付いてしまい、設定ファイルをGitなどで管理するときに気になります。

次のようにseparatorsを指定してあげると行末空白を取り除くことができます。

with open('conf.json', 'w') as conf_file:
    json.dump(conf, conf_file, indent=4, separators=(',', ': '))

参考

最初に見つけた回答 Issue 16333: Trailing whitespace in json dump when using indent - Python tracker

公式ドキュメントでは以下のように書いてあります。

separators がタプル (item_separator, dict_separator) ならば、デフォルト区切り文字 (', ', ': ') の代わりに使われます。 (',', ':') が最もコンパクトな JSON の表現です。

サンプル

順番通りにloadして、新しい設定を追加して、行末空白なしで、元の順番通りに書き出す例

# -*- coding:utf-8 -*-
import json
import collections


decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
with open('conf.json') as conf_file:
    conf = decoder.decode(conf_file.read())

conf['New.Key'] = 'append last'

with open('conf.json', 'w') as conf_file:
    json.dump(conf, conf_file, indent=4, separators=(',', ': '))

この2つは設定ファイル扱う上で今後は無くてはならない感じになりそうです。勉強になった!