On Sat, 17 Aug 2019 at 08:28, Andrew Barnert via Python-ideas
<python-ideas@python.org> 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 -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/P4E3G7NCZWHTOZHCXVMVALOBV2JEDGWJ/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to