Convert Python Objects to JSON (Ordered Keys)

In the JSON output shown in the last post, the keys are printed out of order since they are unordered in the internal dictionary __dict__. In theory, it does not matter to machines when converting to/from JSON. However, it sometimes makes sense to humans for the keys to be pretty-printed in order, especially when we need to look for two keys in JSON next to each other or one key before another.

For example, in the Config object in the last post, it is better to see source and target configurations side by side and, then, get to know what kind of tests from testName key before reading details of tests in queries key. Setting sort_keys option in json.dump is not applicable here since the keys will be sorted by their names, not their order of appearance like we do in the Java example.

To have the keys appear in order as defined when converting to JSON, we have two options:

Option 1: use OrderedDict as your base class

This option is just a quick and dirty workaround: our Config class should extend collections.OrderedDict class and, in the code, we refer to object["att"] instead of object.att.

We have some extra typing, but in general, it is good enough for some configuration objects. Note that you can now dump your configuration object directly into file because it now behaves like a dictionary.

Option 2: use OrderedDict as your attribute dictionary.

In order to refer to attributes directly as object.att and still get JSON ordered like in the Java example, it will need some works. Note that the obvious solution __dict__ = OrderedDict() will NOT work due to a Python bug.

I got an empty object as my JSON output. It can be pretty confusing since we can still refer to attributes using standard notation object.att and correctly retrieve values. After searching the web, I finally figured out that it is a known bug, as documented here. It says that if __dict__ is not an actual dict(), then it is ignored, and attribute lookup fails if using that dictionary directly.

To work around that problem, we have to use OrderedDict as an attribute in __dict__ and modify __getattr__ and __setattr__ methods to use this OrderedDict instead. The modified Config class and modified default= parameter is shown below.

The JSON output now has the keys appear in the order as they are defined, similar to Jackson example above:

With that, for configuration editing purposes, using the Python object to JSON conversion is more convenient than Java (POJO) to JSON conversion. We can add new custom attributes if needed without having to define a new class. The Config class is all you need for all configuration writing. The full working code for converting Python object to JSON is shown below.