On Sat, 17 Aug 2019 at 08:28, Andrew Barnert via Python-ideas
<[email protected]> wrote:
> def jsonize_my_tree(obj):
> if isinstance(obj, MyTreeNode):
> return [obj.data(), *map(jsonize_my_tree, obj.children())]
> raise TypeError()
>
> myjson = json.dumps(my_thing_that_might_include_trees,
> default=jsonize_my_tree)
>
> This is only mildly inconvenient. But it does become worse if you have lots
> of classes you want to serialize. You need to write a default function
> somewhere that knows about all of your classes:
>
> def jsonize_my_things(obj):
> if isinstance(obj, MyTreeNode):
> return [obj.data(), jsonize_my_tree(obj.children())]
> if isinstance(obj, MyRational):
> return {'Fraction', obj.numerator, obj.denominator}
> if isinstance(obj, MyWinUTF16String):
> return str(obj)
> # …
> raise TypeError()
>
> Or you need to come up with a registry, or a protocol, or a singledispatch
> overload set, or some other way to let you write a separate function for each
> class and automatically combine them into one function you can pass to the
> default argument.
This is pretty much exactly what singledispatch is designed for:
@singledispatch
def jsonize(obj):
raise TypeError(f"Cannot serialise {type(obj)} to JSON")
@jsonize.register
def _(obj: MyTreeNode):
return [obj.data(), *map(jsonize_my_tree, obj.children())]
@jsonize.register
def _(obj: MyRational):
return {'Fraction', obj.numerator, obj.denominator}
@jsonize.register
def _(obj: MyWinUTF16String):
return str(obj)
myjson = json.dumps(my_thing_that_might_include_trees, default=jsonize)
If you want to support a __json__ method as well, you can even do:
@singledispatch
def jsonize(obj):
__json__ = getattr(obj, '__json__', None)
if __json__ and callable(__json__):
return __json__(obj)
raise TypeError(f"Cannot serialise {type(obj)} to JSON")
I honestly think singledispatch is under-used, and could avoid the
need for many of the new protocols people like to propose.
(Note: The proposal to support Decimal would *not* be handled by this,
as the "default" argument to json.dumps requires you to go through an
already-supported type. But that's a separate concern here).
Paul
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/P4E3G7NCZWHTOZHCXVMVALOBV2JEDGWJ/
Code of Conduct: http://python.org/psf/codeofconduct/