3
1

PythonでJSON 書き込み

Last updated at Posted at 2024-03-17

早めの結論

  • json に変換するには json.dumps 関数を使用する
  • json ファイルに書き込むには json.dump 関数を使用する
  • 変換できない型には defalut を指定すると良い
  • 変換前後の型対応についてはこちら

json に変換する

import json

# json に書き込むデータ
target_dict = {
    "int": 42,
    "float": 0.5,
    "bool_true": True,
    "bool_false": False,
    "none": None,
    "str": "spam",
    "list": ["eggs", "ham"],
    "tapple": ("this", "is", "tapple", 42),
    "dict": {"key1": 1, "key2": 2}
}

# json にする
target_dumped_str = json.dumps(target_dict)

出力結果

json に変換したデータ target_dumped_str の中身は以下です

(
    '{
        "int": 42,
        "float": 0.5,
        "bool_true": true,
        "bool_false": false,
        "none": null,
        "str": "spam",
        "list": ["eggs", "ham"],
        "tapple": ["this", "is", "tapple", 42],
        "dict": {"key1": 1, "key2": 2}
    }'
)

json ファイルに書き込む

おつぎは,json ファイルに書き込みたいと思います

import json

# json に書き込むデータ
target_dict = {
    "int": 42,
    "float": 0.5,
    "bool_true": True,
    "bool_false": False,
    "none": None,
    "str": "spam",
    "list": ["eggs", "ham"],
    "tapple": ("this", "is", "tapple", 42),
    "dict": {"key1": 1, "key2": 2}
}

# ファイルに書き込む
with open("qiita_write.json", mode="w", encoding="utf-8") as f:
    json.dump(target_dict, f)

出力結果

qiita_write.json
{
    "int": 42,
    "float": 0.5,
    "bool_true": true,
    "bool_false": false,
    "none": null,
    "str": "spam",
    "list": ["eggs", "ham"],
    "tapple": ["this", "is", "tapple", 42],
    "dict": {"key1": 1, "key2": 2}
}

型の対応

ここまで書き込みを見てきましたが,

  • 変換した後の型はどうなってるの?
  • あの型は変換できるの?

など型について疑問に思った方もいるかと思います.

ということでまずは型の対応を見てみましょう.

デコードの対応(JSON → Python)

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

公式ドキュメント

エンコードの対応(Python → JSON)

Python JSON
dict object
list, tupple array
str string
int, float, int- & float-derived Enums number
True true
False false
None null

公式ドキュメント

変換できない型の対処

上記で型の対応を見ましたが,Decimaldatatime などはどうなるのでしょうか...?
ということでやってみましょう.

変換チャレンジ

import json
from decimal import Decimal

# エラーになるデータ
error_dict = {
    "decimal": Decimal("42"),
}

# json にする
target_dumped_str = json.dumps(error_dict, default=json_type_handle)

出力結果

TypeError: Decimal('42') is not JSON serializable

エラーが出ましたね...

対処法

  1. JSON で対応できるように変換する関数を作る
  2. 書き込む関数の引数 defalut に 1 で作成した関数を指定する

JSON で対応できるように変換する関数を作る

def json_type_handle(target):
    """"変換できない値を json で扱える値に変換する"""

    if isinstance(target, Decimal):
        return float(target)
    
    if isinstance(target, datetime):
        return target.isoformat()
    
    raise TypeError(f"{repr(target)} is not JSON serializable")

中身としては以下の通りです.

  • isinstance 関数で型をチェックし,変換して返す
    • Decimal の場合は float に変換して返す
    • datatime の場合は isoformat 関数で文字列に変換して返す
  • どれにも該当しなかったら例外を送出する

書き込む関数の引数 defalut に作成した関数を指定する

default="作成した関数名" で指定します.
以下具体例です.

# json にする
target_dumped_str = json.dumps(error_dict, default=json_type_handle)
pprint.pprint(target_dumped_str)

# ファイルに書き込む
with open("qiita_write_error_handle.json", mode="w", encoding="utf-8") as f:
    json.dump(error_dict, f, default=json_type_handle)

全体像

ということで全体像を見てみましょう.

import json
from decimal import Decimal
from datetime import datetime


# エラーになるデータ
error_dict = {
    "decimal": Decimal("42"),
    "datatime": datetime.now(),
}


def json_type_handle(target):
    """"変換できない値を json で扱える値に変換する"""

    if isinstance(target, Decimal):
        return float(target)
    
    if isinstance(target, datetime):
        return target.isoformat()
    
    raise TypeError(f"{repr(target)} is not JSON serializable")

# json にする
target_dumped_str = json.dumps(error_dict, default=json_type_handle)
pprint.pprint(target_dumped_str)

# ファイルに書き込む
with open("qiita_write_error_handle.json", mode="w", encoding="utf-8") as f:
    json.dump(error_dict, f, default=json_type_handle)

読み込むとき

上記の例では,

  • Decimal → flaot
  • datatime → str

に変換しました.
逆に json を読み込んで Python で扱うときに,

  • float → Decimal
  • str → datatime

に変換したいとします.

# float を Decimal に変換して読み込む
target_loaded_str = json.loads(target_dumped_str, parse_float=Decimal,)

# str に変換されている datatime を datatime に変換する
datetime.fromisoformat(target_loaded_str.get("datatime"))

出力してみるとこんな感じです.

{'datatime': '2024-03-17T12:52:01.528393', 'decimal': Decimal('42.0')}
2024-03-17 12:52:01.528393

これで書き込みもばっちりですね!!
お疲れさまでした!!

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1