Skip to content Skip to sidebar Skip to footer

Why Doesn't Jsonencoder Work For Namedtuples?

I am unable to to dump collections.namedtuple as correct JSON. First, consider the official example for using custom JSON serializer: import json class ComplexEncoder(json.JSONEnc

Solution 1:

As I said in a comment, the json.JSONEncoder only calls default when it encounters an object type it doesn't already know how to serialize itself. There's a table of them in the json documentation. Here's a screenshot of it for easy reference:

table of types supported by default

Note that tuple is on the list, and since namedtuple is a subclasses of tuple, it applies to them, too. (i.e. because isinstance(friend_instance, tuple)True).

This is why your code for handling instances of the Friend class never gets called.

Below is one workaround — namely by creating a simple Wrapper class whose instances won't be a type that the json.JSONEncoder thinks it already knows how to handle, and then specifying a default= keyword argument function that's to be called whenever an object is encountered that it doesn't already know how to do.

Here's what I mean:

import json
from collections import namedtuple

classWrapper(object):
    """ Container class for objects with an _asdict() method. """def__init__(self, obj):
        asserthasattr(obj, '_asdict'), 'Cannot wrap object with no _asdict method'
        self.obj = obj


if __name__ == '__main__':

    Friend = namedtuple("Friend", ["id", 'f_name', 'l_name'])
    t = Friend(21, 'Steve', 'Rogerson')
    print(t)
    print(json.dumps(t))
    print(json.dumps(Wrapper(t), default=lambda wrapper: wrapper.obj._asdict()))

Output:

Friend(id=21, f_name='Steve', l_name='Rogerson')
[21, "Steve", "Rogerson"]
{"id": 21, "f_name": "Steve", "l_name": "Rogerson"}

For some additional information and insights, also check out my answer to the related question Making object JSON serializable with regular encoder.

Post a Comment for "Why Doesn't Jsonencoder Work For Namedtuples?"