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/