我有一个嵌套OrderedDict
我想转换为dict
。在其上应用dict()
显然只会转换最后一个条目的最外层。
from collections import OrderedDict
od = OrderedDict(
[
(u'name', u'Alice'),
(u'ID', OrderedDict(
[
(u'type', u'card'),
(u'nr', u'123')
]
)),
(u'name', u'Bob'),
(u'ID', OrderedDict(
[
(u'type', u'passport'),
(u'nr', u'567')
]
))
]
)
print(dict(od))
输出:
{u'name': u'Bob', u'ID': OrderedDict([(u'type', u'passport'), (u'nr', u'567')])}
是否有直接的方法来转换所有出现的情况?
答案 0 :(得分:23)
最简单的解决方案是使用json转储和加载
from json import loads, dumps
from collections import OrderedDict
def to_dict(input_ordered_dict):
return loads(dumps(input_ordered_dict))
注意:上面的代码适用于json已知为可序列化对象的字典。可以找到默认对象类型列表here
因此,如果有序字典不包含特殊值,这应该足够了。
编辑:根据评论,让我们改进上面的代码。让我们说,input_ordered_dict
可能包含默认情况下json无法序列化的自定义类对象。
在这种情况下,我们应该使用default
json.dumps
参数和我们的自定义序列化程序。
(例如):
from collections import OrderedDict as odict
from json import loads, dumps
class Name(object):
def __init__(self, name):
name = name.split(" ", 1)
self.first_name = name[0]
self.last_name = name[-1]
a = odict()
a["thiru"] = Name("Mr Thiru")
a["wife"] = Name("Mrs Thiru")
a["type"] = "test" # This is by default serializable
def custom_serializer(obj):
if isinstance(obj, Name):
return obj.__dict__
b = dumps(a)
# Produces TypeError, as the Name objects are not serializable
b = dumps(a, default=custom_serializer)
# Produces desired output
此示例可以进一步扩展到更大的范围。我们甚至可以根据需要添加过滤器或修改值。只需将其他部分添加到custom_serializer
函数
def custom_serializer(obj):
if isinstance(obj, Name):
return obj.__dict__
else:
# Will get into this if the value is not serializable by default
# and is not a Name class object
return None
在自定义序列化程序的情况下,顶部给出的函数应该是:
from json import loads, dumps
from collections import OrderedDict
def custom_serializer(obj):
if isinstance(obj, Name):
return obj.__dict__
else:
# Will get into this if the value is not serializable by default
# and is also not a Name class object
return None
def to_dict(input_ordered_dict):
return loads(dumps(input_ordered_dict, default=custom_serializer))
答案 1 :(得分:5)
这应该有效:
import collections
def deep_convert_dict(layer):
to_ret = layer
if isinstance(layer, collections.OrderedDict):
to_ret = dict(layer)
try:
for key, value in to_ret.items():
to_ret[key] = deep_convert_dict(value)
except AttributeError:
pass
return to_ret
虽然正如jonrsharpe所说,可能没有理由这样做 - OrderedDict
(按设计)可以在dict
的任何地方使用。
答案 2 :(得分:2)
注意:这个答案只是部分正确,请查看https://stackoverflow.com/a/25057250/1860929以了解更多关于字母大小相同的原因。
原始答案
这并没有回答转换的问题,更多的是关于需要做什么。
OrderedDict是Dict大小两倍的基本假设是有缺陷的。检查一下:
import sys
import random
from collections import OrderedDict
test_dict = {}
test_ordered_dict = OrderedDict()
for key in range(10000):
test_dict[key] = random.random()
test_ordered_dict[key] = random.random()
sys.getsizeof(test_dict)
786712
sys.getsizeof(test_ordered_dict)
786712
基本上两者都是相同的大小。
但是,操作所用的时间并不相同,事实上,创建一个大字典(使用100-10000个键)比创建具有相同键的OrderedDict快大约7-8倍。 (使用%timeit
){/ 1>中的ipython
验证
import sys
import random
from collections import OrderedDict
def operate_on_dict(r):
test_dict = {}
for key in range(r):
test_dict[key] = random.random()
def operate_on_ordered_dict(r):
test_ordered_dict = OrderedDict()
for key in range(r):
test_ordered_dict[key] = random.random()
%timeit for x in range(100): operate_on_ordered_dict(100)
100 loops, best of 3: 9.24 ms per loop
%timeit for x in range(100): operate_on_dict(100)
1000 loops, best of 3: 1.23 ms per loop
因此,IMO,您应该专注于直接将数据读入dict
并对其进行操作,而不是先创建OrderedDict
,然后重复将其转换为dict。
答案 3 :(得分:0)
我编写了一个递归方法,将OrderedDict
转换为简单的字典。
def recursive_ordered_dict_to_dict(ordered_dict):
simple_dict = {}
for key, value in ordered_dict.items():
if isinstance(value, OrderedDict):
simple_dict[key] = recursive_ordered_dict_to_dict(value)
else:
simple_dict[key] = value
return simple_dict
注意:OrderedDict
和dict
通常是可以互换的,但在使用assert
在两种类型之间运行pytest
时遇到了问题。
答案 4 :(得分:0)
这是一个还可以处理列表和元组的版本。在此comment中,OP提到了字典列表也是一种处理情况。
注意,这也会将元组转换为列表。保存元组留给读者练习:)
APP_VERSION: ${APP_VERSION}
BUILD_NUMBER: ${BUILD_NUMBER}
答案 5 :(得分:0)
此代码应适用于嵌套列表。
def nested_convert_to_dict(input: [dict, collections.OrderedDict]):
if isinstance(input, collections.OrderedDict):
res = dict(input)
else:
res = input
try:
for key, value in res.items():
res[key] = nested_convert_to_dict(value)
if isinstance(value, list):
new_value = []
for item in value:
if isinstance(item, collections.OrderedDict):
item = nested_convert_to_dict(item)
new_value.append(item)
res[key] = new_value
except AttributeError:
pass
return res