Issue 30343: Subclassed json.JSONEncoder does not respect default method for supported types (original) (raw)

If you subclass json.JSONEncoder to enable serialisation of custom types beyond those supported, you are meant to transform values of said type into a serialisable version within an overridden default method. For example:

class MyJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, MyType):
            return str(o)

        # Raise TypeError when we have a type we can't serialise
        super().default(o)

This, however, won't work if your custom type is an instance of one of the supported types. This is because, in Lib/json/encoder.py, the _iterencode function (defined in _make_iterencode) type checks against supported types before it delegates to the default method.

The reason this came up is because I wanted to serialise a named tuple into a JSON object, with keys corresponding to the named tuple's field names. Ignoring the merits (or otherwise) of this desired outcome, this can't work because a named tuple is still a tuple and thus the default method is never called.

In Python 2.7, the _iterencode method was part of the JSONEncoder class, so you could override it in a subclass; even if doing so is somewhat brittle. In Python 3, this method has been moved out into the module namespace (tested in 3.6; looking through the repo, it looks like this change was made in Python 3.1), so it can't easily be monkey-patched without it affecting other things.

I believe this to be a bug. It seems reasonable to subclass at least named tuples, dictionaries and lists in such a way that you'd want a different JSON serialisation to their defaults.