This thread discusses a __json__ encoder protocol:
"adding support for a "raw output" in JSON serializer" https://email@example.com/thread/WT6Z6YJDEZXKQ6OQLGAPB3OZ4OHCTPDU/
You actually don't have to subclass JSONEncoder; you can specify a default= method that uses isinstance(), hasattr(), or singledispatch.
- "Specializing JSON object encoding:"
> If for_json is true (not the default), objects with a for_json() method will use the return value of that method for encoding as JSON instead of the object.
"use __json__ attribute to encode custom objects"
Simplejson supports object.for_json(), but only checks objects if for_json=True is specified.
FWIW, Jupyter notebook supports object._repr_json_() and e.g. object._repr_pretty_()
Dunder methods are name-mangled, and, by convention reserved for internal Python use: if CPython decides that object.__json__() should return a bool for whether a string is already JSON-encoded, and that breaks your excessively-presumptive dunder json method implementation, tough luck.
Singledispatch (or, indeed, creating your own utils.json.dump that's a functools.partial that just specifies a default default=) is probably fastest.
JSON5 allows things like ±inf and nan.