Can I get JSON to load into an OrderedDict?
Yes, you can. By specifying the object_pairs_hook
argument to JSONDecoder. In fact, this is the exact example given in the documentation.
>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>>
You can pass this parameter to json.loads
(if you don't need a Decoder instance for other purposes) like so:
>>> import json
>>> from collections import OrderedDict
>>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict)
>>> print json.dumps(data, indent=4)
{
"foo": 1,
"bar": 2
}
>>>
Using json.load
is done in the same way:
>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)
json.loads() doesn't keep order
Both JSON en Python dictionaries (those are JSON objects) are unordered. So in fact it does not makes any sense to do that, because the JSON encoder can change the order.
You can however define a custom JSON decoder, and then parse it with that decoder. So here the dictionary hook willl be an OrderedDict
:
from json import JSONDecoder
from collections import OrderedDict
customdecoder = JSONDecoder(object_pairs_hook=OrderedDict)
Then you can decode with:
customdecoder.decode(your_json_string)
This will thus store the items in an OrderedDict
instead of a dictionary. But be aware - as said before - that the order of the keys of JSON objects is unspecified.
Alternatively, you can also pass the hook to the loads
function:
from json import loads
from collections import OrderedDict
loads(your_json_string, object_pairs_hook=OrderedDict)
Update: as of python-3.7, a dictionary retains insertion order. So if one uses python-3.7, the standard
json.load
andjson.loads
should work fine. Note however that a JSON object is still unordered, so that the JavaScript end can load/dump the object in any order.
Json to OrderedDict in Python
You have the keyword argument in the wrong place, which may be clearer if we add more whitespace:
data = OrderedDict(
json.loads(
resp.read().decode("utf-8") # one argument to json.loads
),
object_pairs_hook=OrderedDict # second argument to OrderedDict
)
OrderedDict
takes no such argument - you meant to pass it to json.loads
, then you don't need to re-create it:
data = json.loads(
resp.read().decode("utf-8"),
object_pairs_hook=OrderedDict
)
The reason you aren't seeing the order you want when you leave out the object_pairs_hook
is that json.loads
is creating a vanilla, unordered dictionary then converting it to an OrderedDict
.
Python json.loads changes the order of the object
Dictionaries (objects) in python have no guaranteed order. So when parsed into a dict
, the order is lost.
If the order is important for some reason, you can have json.loads
use an OrderedDict
instead, which is like a dict
, but the order of keys is saved.
from collections import OrderedDict
data_content = json.loads(input_data.decode('utf-8'), object_pairs_hook=OrderedDict)
How do I update my dictionary with values from JSON?
Instead of processing the data after it has been loaded - you can pass custom functions to json.load / loads which can simplify extraction:
ordered_keys = ("leaveGroup", "functionalCode", "DFASUnionCode", "normalHours")
order_dic_keys = OrderedDict.fromkeys(ordered_keys)
def extract_data(obj):
for key, value in obj:
if key in order_dic_keys:
order_dic_keys[key] = value
>>> json.loads(data, object_pairs_hook=extract_data)
>>> order_dic_keys
OrderedDict([('leaveGroup', '2'),
('functionalCode', '00'),
('DFASUnionCode', None),
('normalHours', 80)])
full code example:
import json
from collections import OrderedDict
def extract_data(obj):
for key, value in obj:
if key in order_dic_keys:
order_dic_keys[key] = value
return dict(obj)
ordered_keys = ("leaveGroup", "functionalCode", "DFASUnionCode", "normalHours")
order_dic_keys = OrderedDict.fromkeys(ordered_keys)
with open("file.json") as f:
json_file = json.load(f, object_pairs_hook=extract_data)
print(order_dic_keys)
understanding object_pairs_hook in json.loads()
It allows you to customize what objects your JSON will parse into. For this specific argument (object_pairs_hook
) it's for pair (read key/value pairs of a mapping object).
For instance if this string appears in your JSON:
{"var1": "val1", "var2": "val2"}
It will call the function pointed to with the following argument:
[('var1', 'val1'), ('var2', 'val2')]
Whatever the function returns is what will be used in the resulting parsed structure where the above string was.
A trivial example is object_pairs_hook=collections.OrderedDict
which ensures your keys to be ordered the same way as they were they occurred in the incoming string.
The generic idea of a hook is to allow you to register a function that is called (back) as needed for a given task. In this specific case it allows you to customize decoding of (different types of objects in the) incoming JSON string.
Related Topics
Using Numpy to Build an Array of All Combinations of Two Arrays
How to Wait Some Time in Pygame
Unicodedecodeerror When Reading CSV File in Pandas With Python
Changing Default Encoding of Python
What Is the Formal Difference Between "Print" and "Return"
How to Prevent Tensorflow from Allocating the Totality of a Gpu Memory
Adding Python to Path on Windows
Why Does the Expression 0 ≪ 0 == 0 Return False in Python
How to Prettyprint a Json File
Error Message: "'Chromedriver' Executable Needs to Be Available in the Path"
How to Iterate Over Files in a Given Directory