早めの結論
- 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 |
変換できない型の対処
上記で型の対応を見ましたが,Decimal
や datatime
などはどうなるのでしょうか...?
ということでやってみましょう.
変換チャレンジ
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
エラーが出ましたね...
対処法
- JSON で対応できるように変換する関数を作る
- 書き込む関数の引数
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
これで書き込みもばっちりですね!!
お疲れさまでした!!
参考