初めに
pythonのdictをJSON文字列にするのは良く行われる処理だと思います
とあるAPIに渡すのに、数値は文字列にしないといけないケースがありました
dictの生成処理で、文字列に変換すれば良いかと思いましたが、
今一つイケていないので、JSON文字列を生成する際に、intもしくはfloatなら文字列にしようと考えました
やってみた
import json
import datetime
class Num2StrEncoder(json.JSONEncoder):
def default(self, o):
print(o) # debug
if isinstance(o, (int, float)):
return str(o)
return super().default(o)
def test_jsondump():
record = {
"aaa": 100,
"bbb": 0,
"ccc": 0.0,
"ddd": 123456789.12345,
"eee": "123",
"fff": "0.0",
# "ggg": datetime.datetime.now(),
}
buf = json.dumps(record, cls=Num2StrEncoder)
print(buf)
上のコードを実行しましたが、defaultメソッドは呼び出されません
考察
下はマニュアルからの抜粋です
(1部改行)
特に呼び出すのに条件はないようです
cls (a JSONEncoder subclass) --
If set, a custom JSON encoder with the default() method overridden,
for serializing into custom datatypes.
If None (the default), JSONEncoder is used.
マニュアルを眺めていて気づいたのがdefalutパラメーターです
(1部改行)
こちらはthat can't otherwise be serialized
なので、JSON文字列に出来ない場合のみ呼ばれるようです
default (callable | None) --
A function that is called for objects that can't otherwise be serialized.
It should return a JSON encodable version of the object or raise a TypeError.
If None (the default), TypeError is raised.
同じdefaultなので気になったので、試しに"ggg": datetime.datetime.now(),
を追加しテストしたところ
test/test_jsondump.py 2025-02-20 13:36:14.728545
{"aaa": 100, "bbb": 0, "ccc": 0.0, "ddd": 123456789.12345, "eee": "123", "fff": "0.0", "ggg": "2025-02-20 13:36:14.
728545"}
となりました
どうやらclsパラメーターもdefaultパラメーターと同じように、規定のserialize可能な型以外のみ呼び出されるようです
規定のserializeは↓となっています
https://docs.python.org/ja/3.13/library/json.html#json.JSONEncoder
終りに
この対応でかなりの時間を溶かしてしまいました
同じ思いをする人が一人でも少なくなりますように