Pythonでjsonの読み込み、出力、変換、整形を行う方法を解説する

スポンサーリンク

Python JSONモジュールに飛び込む前に、JSONが何であるかを理解しましょう。

JSON(JavaScript Object Notation)は、インターネット上でデータを交換するための標準化されたフォーマットです。

これはインターネットを介したあらゆる情報交換の標準となっているため、Pythonアプリケーションがこの形式を使ってデータを送受信することは理にかなっています。

Pythonの組み込みのjsonモジュールは、PythonオブジェクトをJSONオブジェクトに変換するインターフェースです。

この記事では、jsonモジュールで最もよく使われるメソッドをいくつか見てみましょう。


スポンサーリンク

JSONオブジェクトのフォーマット

モジュールの詳細に入る前に、JSONオブジェクトがどのような構成になっているかを理解しましょう。

これは実際にはPythonの辞書と非常によく似ており、{Key: Value}のペアのセットを持ちます。

唯一の小さな違いは、JSONオブジェクトには開閉用の中括弧があることです。

以下はJSONオブジェクトの簡単な例です。

{
    "name": "John",
    "age": 42,
    "married": True,
    "qualifications": ["High School Diploma", "Bachelors"]
}

JSONオブジェクトは、文字列や整数、あるいはリストなど、さまざまな属性から構成することができます。

JSONオブジェクトの構成がわかったところで、Pythonのjsonモジュールのメソッドを見てみましょう。


Python の json モジュールをインポートする

Pythonにはすでにjsonモジュールが用意されているので、pipを使ってインストールする必要はありません。

このモジュールをインポートするには、次のように入力するだけです。

import json

json.dumps() – JSON オブジェクトを生成する

json.dumps()` メソッドを使うと、Python オブジェクトを JSON オブジェクトにエンコードすることができます。

dumps()` は Python オブジェクトを Python JSON オブジェクトにシリアライズして文字列を返すと考えることができます。

これは、インターネット上でデータを転送したい場合に必要となります。

エンコードされたデータは、異なるPythonオブジェクトに対して、以下の表で言及されています。

Python JSON
ディクショナリー|オブジェクト|リスト|タプル|配列
リスト、タプル、配列
str|文字列
int, float, int- & float派生Enums|number|(数値
真|真|真|真
偽|False|フォールス
なし(None) ヌル(Null)

これは引数としてシリアライズ可能な任意のPythonオブジェクトを取り、文字列を返します。

形式は

json_object = json.dumps(serializable_object)

ここで、serializable_object はリストや文字列などのシリアライズ可能なPythonオブジェクトです。

関数やラムダなどにはできない。

import json
 
python_object = ['Hello', 'from', 'Python', 42]
 
json_object = json.dumps(python_object)
 
print(type(json_object), json_object)

結果は以下の通りです。

<class 'str'> ["Hello", "from", "Python", 42]

このメソッドは、オブジェクトがシリアライズ可能でない場合、 TypeError を発生させる。

>>> import json
>>> a = lambda x : x * 2
>>> a(2)
4
>>> json.dumps(a)
Traceback (most recent call last):
    raise TypeError(f'Object of type {o.__class__.__name__}
TypeError: Object of type function is not JSON serializable

Dictのキーの並べ替え

json.dumps()に Python 辞書を渡す場合、別のパラメータsort_keys` を指定すると、Python の json オブジェクトをソートしたキーを持つようにすることができます。

import json
 
dict_obj = {1:"one", 20: "twenty", 5:"five"}
 
json_obj = json.dumps(dict_obj, sort_keys = True)
 
print(json_obj)

結果は以下の通りです。

{"1": "one", "5": "five", "20": "twenty"}

出力は確かにソートされたキーを持っています。

注:JSONにエンコードされているため、数値は文字列に変換されています。

適切なメソッドでデシリアライズして整数に戻せばよい。

PythonのJSONオブジェクトをきれいに印刷する

json.dumps()indentパラメータを使って、インデントレベルを指定することができます。

通常、indent = 4` とすると、出力がとてもきれいになります。

import json
 
dict_obj = {1:"one", 20: "twenty", 5:"five"}
 
json_obj = json.dumps(dict_obj, sort_keys = True, indent = 4)
 
print(json_obj)

結果は以下の通りです。

{
    "1": "one",
    "5": "five",
    "20": "twenty"
}

json.dump() – ファイルにダンプする

別のメソッド json.dump() を使って、オブジェクトをファイルにダンプすることもできます。

形式は以下の通りです。

json.dump(data, file_object)

json.dump()`メソッドはデータを取り込み、ファイルオブジェクトに書き込みます。

つまり、新しいファイルを開き、そのファイルオブジェクトに json.dump() を使って書き込めばよいのです。

import json
 
python_object = ['Hello', 'from', 'Python', 42]
 
with open("sample.json", "w") as wf:
    json.dump(python_object, wf)

結果は以下の通りです。

user@Python $ cat sample.json
["Hello", "from", "Python", 42]

見ての通り、Pythonオブジェクトは確かにファイルにダンプされました。

では、最初の例で示したJSONオブジェクトをファイルに保存してみましょう。

import json
 
json_object = {
    "name": "John",
    "age": 42,
    "married": True,
    "qualifications": ["High School Diploma", "Bachelors"]
}
 
with open("sample.json", "w") as wf:
    json.dump(json_object, wf)

結果は以下の通りです。

user@Python $ cat sample.json
{"name": "John", "age": 42, "married": true, "qualifications": ["High School Diploma", "Bachelors"]}

JSONオブジェクトのデシリアライズ

PythonオブジェクトをJSONオブジェクトにエンコードするのと同様に、JSONオブジェクトをPythonオブジェクトに変換することで、その逆を行うことも可能です。

これはデシリアライゼーションと呼ばれます。

これは json.loads()json.load() というメソッドを用いて行うことができます。

これは json.dumps()json.dump() と同じようなメソッドです。

json.loads()

これは json.dumps() でエンコードされた json オブジェクトを Python オブジェクトに変換します。

import json
 
python_object = ['Hello', 'from', 'Python', 42]
 
encoded_object = json.dumps(python_object)
 
decoded_object = json.loads(encoded_object)
 
print(type(decoded_object), decoded_object)

結果は以下の通りです。

<class 'list'> ['Hello', 'from', 'Python', 42]

無事、古いリストオブジェクトを取り戻すことができました!

json.load() – ファイルからのデシリアライズ

これは json.dump() の逆の操作で、json オブジェクトをファイルから Python オブジェクトに変換して返します。

このメソッドを使って、sample.json ファイルを取り出し、データを取得してみましょう。

import json
 
with open("sample.json", "r") as rf:
    decoded_data = json.load(rf)
 
print(decoded_data)

結果は以下の通りです。

{'name': 'John', 'age': 42, 'married': True, 'qualifications': ['High School Diploma', 'Bachelors']}

確かに、ファイルに保存した古いJSONオブジェクトを再び取得することができました。

さて、このモジュールで最もよく使われるメソッドをカバーしたので、次のステップに進みましょう。


独自のJSONエンコーダを作成する

jsonモジュールはjson.JSONEncoder` というエンコーダーを使用しています。

このエンコーダーは、上に示した表のルールに従って Python オブジェクトをエンコードしています。

しかし、これはすべてのPythonオブジェクトをエンコードするわけではなく、直面する問題によっては、それらのオブジェクトを特別な方法でエンコードするために、独自のJSONエンコーダを書く必要があるかもしれません。

そのためには、独自のEncoderクラスを書く必要があります。

これを MyEncoder と呼ぶことにしましょう。

これは json.JSONEncoder クラスを継承して、その既存の機能を追加する必要があります。

このデモでは、numpyの配列を受け取り、PythonのJSONオブジェクトに変換することにします。

jsonモジュールはデフォルトでnumpyの配列を扱えないので、拡張クラスなしでnumpyの配列を変換しようとすると、TypeErrorが発生します。

TypeError: Object of type ndarray is not JSON serializable

では、このクラスを使って、numpyの配列をPythonのリストに変換して、jsonオブジェクトにシリアライズ、エンコードする方法を書いてみましょう。

import json
import numpy as np
 
class MyEncoder(json.JSONEncoder):
    # Handles the default behavior of
    # the encoder when it parses an object 'obj'
    def default(self, obj):
        # If the object is a numpy array
        if isinstance(obj, np.ndarray):
            # Convert to Python List
            return obj.tolist()
        else:
            # Let the base class Encoder handle the object
            return json.JSONEncoder.default(self, obj)
 
 
# Numpy array of floats
a = np.arange(1, 10, 0.5)
print(type(a), a)
 
# Pass our encoder to json.dumps()
b = json.dumps(a, cls=MyEncoder)
print(b)

最後に、json.dumps()cls パラメータにクラス名を渡して、エンコードしています。

つまり、エンコーディングの呼び出しは次のようになります。

json_object = json.dumps(python_object, cls=MyEncoder)

結果は以下の通りです。

<class 'numpy.ndarray'> [1.  1.5 2.  2.5 3.  3.5 4.  4.5 5.  5.5 6.  6.5 7.  7.5 8.  8.5 9.  9.5]
[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]

これで、私たちのカスタムエンコーダーはnumpyの配列をJSONオブジェクトに変換することができるようになりました! これで、最初の複雑なエンコーダが完成しました。

この機能を拡張して、あなたの特定のユースケースのために異なるエンコーダを書くことができます!


まとめ

今回は、Pythonの json モジュールを使って、JSONオブジェクトを含むさまざまな操作を行う方法を学びました。


タイトルとURLをコピーしました