What is the recommended way of serializing a namedtuple
to json with the field names retained?
Serializing a namedtuple
to json results in only the values being serialized and the field names being lost in translation. I would like the fields also to be retained when json-ized and hence did the following:
class foobar(namedtuple('f', 'foo, bar')):
__slots__ = ()
def __iter__(self):
yield self._asdict()
The above serializes to json as I expect and behaves as namedtuple
in other places I use (attribute access etc.,) except with a non-tuple like results while iterating it (which fine for my use case).
What is the "correct way" of converting to json with the field names retained?
It looks like you used to be able to subclass
simplejson.JSONEncoder
to make this work, but with the latest simplejson code, that is no longer the case: you have to actually modify the project code. I see no reason why simplejson should not support namedtuples, so I forked the project, added namedtuple support, and I'm currently waiting for my branch to be pulled back into the main project. If you need the fixes now, just pull from my fork.EDIT: Looks like the latest versions of
simplejson
now natively support this with thenamedtuple_as_object
option, which defaults toTrue
.This is an old question. However:
A suggestion for all those with the same question, think carefully about using any of the private or internal features of the
NamedTuple
because they have before and will change again over time.For example, if your
NamedTuple
is a flat value object and you're only interested in serializing it and not in cases where it is nested into another object, you could avoid the troubles that would come up with__dict__
being removed or_as_dict()
changing and just do something like (and yes this is Python 3 because this answer is for the present):I tried to use the
default
callable kwarg todumps
in order to do theto_dict()
call if available, but that didn't get called as theNamedTuple
is convertible to a list.I wrote a library for doing this: https://github.com/ltworf/typedload
It can go from and to named-tuple and back.
It supports quite complicated nested structures, with lists, sets, enums, unions, default values. It should cover most common cases.
If it's just one
namedtuple
you're looking to serialize, using its_asdict()
method will work (with Python >= 2.7)It recursively converts the namedTuple data to json.
This is pretty tricky, since
namedtuple()
is a factory which returns a new type derived fromtuple
. One approach would be to have your class also inherit fromUserDict.DictMixin
, buttuple.__getitem__
is already defined and expects an integer denoting the position of the element, not the name of its attribute:At its heart the namedtuple is an odd fit for JSON, since it is really a custom-built type whose key names are fixed as part of the type definition, unlike a dictionary where key names are stored inside the instance. This prevents you from "round-tripping" a namedtuple, e.g. you cannot decode a dictionary back into a namedtuple without some other a piece of information, like an app-specific type marker in the dict
{'a': 1, '#_type': 'foobar'}
, which is a bit hacky.This is not ideal, but if you only need to encode namedtuples into dictionaries, another approach is to extend or modify your JSON encoder to special-case these types. Here is an example of subclassing the Python
json.JSONEncoder
. This tackles the problem of ensuring that nested namedtuples are properly converted to dictionaries: