Reputation: 1551
I am struggling with the following problem:
I want to convert an OrderedDict
like this:
OrderedDict([('method', 'constant'), ('data', '1.225')])
into a regular dict like this:
{'method': 'constant', 'data':1.225}
because I have to store it as string in a database. After the conversion the order is not important anymore, so I can spare the ordered feature anyway.
Thanks for any hint or solutions,
Ben
Upvotes: 151
Views: 157053
Reputation: 18182
If your data structure might contain internal (nested) OrderedDict
instances, you should leverage Python's builtin copy
mechanism.
You can override copying behavior for OrderedDict
via Python's copyreg
module (also used by pickle
). Then you can use Python's builtin copy.deepcopy()
function to perform the conversion.
import copy
import copyreg
from collections import OrderedDict
def convert_nested_ordered_dict(x):
"""
Perform a deep copy of the given object, but convert
all internal OrderedDicts to plain dicts along the way.
Args:
x: Any pickleable object
Returns:
A copy of the input, in which all OrderedDicts contained
anywhere in the input (as iterable items or attributes, etc.)
have been converted to plain dicts.
"""
# Temporarily install a custom pickling function
# (used by deepcopy) to convert OrderedDict to dict.
orig_pickler = copyreg.dispatch_table.get(OrderedDict, None)
copyreg.pickle(
OrderedDict,
lambda d: (dict, ([*d.items()],))
)
try:
return copy.deepcopy(x)
finally:
# Restore the original OrderedDict pickling function (if any)
del copyreg.dispatch_table[OrderedDict]
if orig_pickler:
copyreg.dispatch_table[OrderedDict] = orig_pickler
Merely by using Python's builtin copying infrastructure, this solution is superior to all other answers presented here, in the following ways:
Works for arbitrary data hierarchies, including nested OrderedDict
s.
Works for more than just JSON data.
Does not require you to implement special logic for each possible element type (e.g. list
, tuple
, etc.)
deepcopy()
will properly handle duplicate objects within the collection:
x = [1,2,3]
d = {'a': x, 'b': x}
assert d['a'] is d['b']
d2 = copy.deepcopy(d)
assert d2['a'] is d2['b']
Since our solution is based on deepcopy()
we'll have the same advantage.
This solution also converts attributes that happen to be OrderedDict
, not only collection elements:
class C:
def __init__(self, a):
self.a = a
def __repr__(self):
return f"C(a={self.a})"
c = C(OrderedDict([(1, 'one'), (2, 'two')]))
print("original: ", c)
print("converted:", convert_nested_ordered_dict(c))
original: C(a=OrderedDict([(1, 'one'), (2, 'two')]))
converted: C(a={1: 'one', 2: 'two'})
Upvotes: 0
Reputation: 41
You can use "dict_constructor" parameters.
xmltodict.parse(text, attr_prefix='',
dict_constructor=dict
)
Upvotes: 4
Reputation: 6841
A version that handles nested dictionaries and iterables but does not use the json
module. Nested dictionaries become dict
, nested iterables become list
, everything else is returned unchanged (including dictionary keys and strings/bytes/bytearrays).
def recursive_to_dict(obj):
try:
if hasattr(obj, "split"): # is string-like
return obj
elif hasattr(obj, "items"): # is dict-like
return {k: recursive_to_dict(v) for k, v in obj.items()}
else: # is iterable
return [recursive_to_dict(e) for e in obj]
except TypeError: # return everything else
return obj
Upvotes: -2
Reputation: 36370
Here is what seems simplest and works in python 3.7
from collections import OrderedDict
d = OrderedDict([('method', 'constant'), ('data', '1.225')])
d2 = dict(d) # Now a normal dict
Now to check this:
>>> type(d2)
<class 'dict'>
>>> isinstance(d2, OrderedDict)
False
>>> isinstance(d2, dict)
True
NOTE: This also works, and gives same result -
>>> {**d}
{'method': 'constant', 'data': '1.225'}
>>> {**d} == d2
True
As well as this -
>>> dict(d)
{'method': 'constant', 'data': '1.225'}
>>> dict(d) == {**d}
True
Cheers
Upvotes: 6
Reputation: 4260
Even though this is a year old question, I would like to say that using dict
will not help if you have an ordered dict within the ordered dict. The simplest way that could convert those recursive ordered dict will be
import json
from collections import OrderedDict
input_dict = OrderedDict([('method', 'constant'), ('recursive', OrderedDict([('m', 'c')]))])
output_dict = json.loads(json.dumps(input_dict))
print output_dict
Upvotes: 104
Reputation: 302
Its simple way
>>import json
>>from collection import OrderedDict
>>json.dumps(dict(OrderedDict([('method', 'constant'), ('data', '1.225')])))
Upvotes: -2
Reputation: 9857
If you are looking for a recursive version without using the json
module:
def ordereddict_to_dict(value):
for k, v in value.items():
if isinstance(v, dict):
value[k] = ordereddict_to_dict(v)
return dict(value)
Upvotes: 6
Reputation: 899
It is easy to convert your OrderedDict
to a regular Dict
like this:
dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))
If you have to store it as a string in your database, using JSON is the way to go. That is also quite simple, and you don't even have to worry about converting to a regular dict
:
import json
d = OrderedDict([('method', 'constant'), ('data', '1.225')])
dString = json.dumps(d)
Or dump the data directly to a file:
with open('outFile.txt','w') as o:
json.dump(d, o)
Upvotes: 10
Reputation: 318778
>>> from collections import OrderedDict
>>> OrderedDict([('method', 'constant'), ('data', '1.225')])
OrderedDict([('method', 'constant'), ('data', '1.225')])
>>> dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))
{'data': '1.225', 'method': 'constant'}
>>>
However, to store it in a database it'd be much better to convert it to a format such as JSON or Pickle. With Pickle you even preserve the order!
Upvotes: 142