tags:

views:

48

answers:

1
import datetime, json
x = {'alpha': {datetime.date.today(): 'abcde'}}
print json.dumps(x)

The above code fails with a TypeError since keys of JSON objects need to be strings. The json.dumps function has a parameter called default that is called when the value of a JSON object raises a TypeError, but there seems to be no way to do this for the key. What is the most elegant way to work around this?

+1  A: 

You can extend json.JSONEncoder to create your own encoder which will be able to deal with datetime.datetime objects (or objects of any type you desire) in such a way that a string is created which can be reproduced as a new datetime.datetime instance. I believe it should be as simple as having json.JSONEncoder call repr() on your datetime.datetime instances.

The procedure on how to do so is described in the json module docs.

The json module checks the type of each value it needs to encode and by default it only knows how to handle dicts, lists, tuples, strs, unicode objects, int, long, float, boolean and none :-)

Also of importance for you might be the skipkeys argument to the JSONEncoder.


After reading your comments I have concluded that there is no easy solution to have JSONEncoder encode the keys of dictionaries with a custom function. If you are interested you can look at the source and the methods iterencode() which calls _iterencode() which calls _iterencode_dict() which is where the type error gets raised.

Easiest for you would be to create a new dict with isoformatted keys like this:

import datetime, json

D = {datetime.datetime.now(): 'foo',
     datetime.datetime.now(): 'bar'}

new_D = {}

for k,v in D.iteritems():
  new_D[k.isoformat()] = v

json.dumps(new_D)

Which returns '{"2010-09-15T23:24:36.169710": "foo", "2010-09-15T23:24:36.169723": "bar"}'. For niceties, wrap it in a function :-)

ikanobori
That only works for values of the dictionary, not keys. There appears to be no way to override encoding of the keys.
ipartola
You are correct, let me find the solution in the source (you can possibly override JSONEncoder.iterencode) as it is not clearly documented.
ikanobori
Okay, I checked the source and it is not possible to make a JSONEncoder instance encode dict keys with a custom function for a certain type easily. You would be best to create a new dict with the keys. I will update my answer to reflect on this.
ikanobori
Thanks. I guess no general purpose way will exist. I guess I should go and see whether at some point this can be corrected in the Python SDL as it seems like a useful feature.
ipartola
The reason why this is done is because there is no 'fail safe' way to convert an object of any kind to the required string type for a json key. It could call repr() or str() on a object which is not basestring but those are not always implemented/useful and Pythons motto is to not do things implicitly which would include doing this.
ikanobori
That makes sense. But having the ability to define this behavior would be nice. It already has the default() method you can override. Why not provide a default_key() method?
ipartola