for k, v in d.iteritems():
if type(v) is dict:
for t, c in v.iteritems():
print "{0} : {1}".format(t, c)
我正在尝试遍历字典并打印出所有值不是嵌套字典的键值对。如果值是字典,我想进入它并打印出其键值对...等。有什么帮助吗?
修改
这个怎么样?它仍然只打印一件事。
def printDict(d):
for k, v in d.iteritems():
if type(v) is dict:
printDict(v)
else:
print "{0} : {1}".format(k, v)
完整测试用例
字典:
{u'xml': {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'},
u'port': u'11'}}
结果:
xml : {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'}
答案 0 :(得分:104)
正如Niklas所说,你需要递归,即你想要定义一个函数来打印你的dict,如果值是一个dict,你想用这个新的dict来调用你的打印函数。
类似的东西:
def myprint(d):
for k, v in d.iteritems():
if isinstance(v, dict):
myprint(v)
else:
print "{0} : {1}".format(k, v)
或者从Python 3开始:
def myprint(d):
for k, v in d.items():
if isinstance(v, dict):
myprint(v)
else:
print("{0} : {1}".format(k, v))
答案 1 :(得分:26)
由于dict
是可迭代的,因此您可以将经典nested container iterable formula应用于此问题,只需进行一些小的更改。这是一个Python 2版本(见下面的3):
import collections
def nested_dict_iter(nested):
for key, value in nested.iteritems():
if isinstance(value, collections.Mapping):
for inner_key, inner_value in nested_dict_iter(value):
yield inner_key, inner_value
else:
yield key, value
测试:
list(nested_dict_iter({'a':{'b':{'c':1, 'd':2},
'e':{'f':3, 'g':4}},
'h':{'i':5, 'j':6}}))
# output: [('g', 4), ('f', 3), ('c', 1), ('d', 2), ('i', 5), ('j', 6)]
在Python 2中,可能可以创建一个符合Mapping
但不包含Mapping
的自定义iteritems
,在这种情况下这会失败。文档未指明iteritems
需要Mapping
;另一方面,source为Mapping
类型提供iteritems
方法。因此,对于自定义Mappings
,请明确继承collections.Mapping
。
在Python 3中,有许多改进。从Python 3.3开始,抽象基类存在于collections.abc
中。它们仍然保留在collections
中以便向后兼容,但是在一个命名空间中将抽象基类放在一起会更好。因此,这会从abc
导入collections
。 Python 3.3还添加了yield from
,它专为这些情况而设计。这不是空的句法糖;这可能会导致faster code与coroutines进行更明智的互动。
from collections import abc
def nested_dict_iter(nested):
for key, value in nested.items():
if isinstance(value, abc.Mapping):
yield from nested_dict_iter(value)
else:
yield key, value
答案 2 :(得分:21)
替代迭代解决方案:
def myprint(d):
stack = d.items()
while stack:
k, v = stack.pop()
if isinstance(v, dict):
stack.extend(v.iteritems())
else:
print("%s: %s" % (k, v))
答案 3 :(得分:20)
如果您编写自己的递归实现或使用堆栈的迭代等效项,则存在潜在问题。见这个例子:
dic = {}
dic["key1"] = {}
dic["key1"]["key1.1"] = "value1"
dic["key2"] = {}
dic["key2"]["key2.1"] = "value2"
dic["key2"]["key2.2"] = dic["key1"]
dic["key2"]["key2.3"] = dic
在通常意义上,嵌套字典将是一个像数据结构一样的n-nary树。但是的定义并不排除交叉边缘甚至后边缘(因此不再是树)的可能性。例如, key2.2 从 key1 保存到字典, key2.3 指向整个字典(后沿/循环)。当存在后沿(循环)时,堆栈/递归将无限运行。
root<-------back edge
/ \ |
_key1 __key2__ |
/ / \ \ |
|->key1.1 key2.1 key2.2 key2.3
| / | |
| value1 value2 |
| |
cross edge----------|
如果您使用 Scharron
中的此实现打印此词典 def myprint(d):
for k, v in d.items():
if isinstance(v, dict):
myprint(v)
else:
print "{0} : {1}".format(k, v)
你会看到这个错误:
RuntimeError: maximum recursion depth exceeded while calling a Python object
senderle 的实施也是如此。
同样地,你从 Fred Foo :
获得了这个实现的无限循环 def myprint(d):
stack = list(d.items())
while stack:
k, v = stack.pop()
if isinstance(v, dict):
stack.extend(v.items())
else:
print("%s: %s" % (k, v))
但是,Python实际上会检测嵌套字典中的循环:
print dic
{'key2': {'key2.1': 'value2', 'key2.3': {...},
'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}}
&#34; {...}&#34; 是检测到周期的地方。
根据 Moondra 的要求,这是一种避免周期的方法(DFS):
def myprint(d):
stack = list(d.items())
visited = set()
while stack:
k, v = stack.pop()
if isinstance(v, dict):
if k not in visited:
stack.extend(v.items())
else:
print("%s: %s" % (k, v))
visited.add(k)
答案 4 :(得分:6)
我编写的版本略有不同,可以跟踪到达目的地的密钥
def print_dict(v, prefix=''):
if isinstance(v, dict):
for k, v2 in v.items():
p2 = "{}['{}']".format(prefix, k)
print_dict(v2, p2)
elif isinstance(v, list):
for i, v2 in enumerate(v):
p2 = "{}[{}]".format(prefix, i)
print_dict(v2, p2)
else:
print('{} = {}'.format(prefix, repr(v)))
在您的数据上,它会打印
data['xml']['config']['portstatus']['status'] = u'good'
data['xml']['config']['target'] = u'1'
data['xml']['port'] = u'11'
如果您需要这样做,也可以很容易地修改它以跟踪前缀作为键的元组而不是字符串。
答案 5 :(得分:4)
这是pythonic的方法。此功能允许您循环遍历所有级别中的键值对。它不会将整个事物保存到内存中,而是在循环中遍历字典
def recursive_items(dictionary):
for key, value in dictionary.items():
if type(value) is dict:
yield (key, value)
yield from recursive_items(value)
else:
yield (key, value)
a = {'a': {1: {1: 2, 3: 4}, 2: {5: 6}}}
for key, value in recursive_items(a):
print(key, value)
打印
a {1: {1: 2, 3: 4}, 2: {5: 6}}
1 {1: 2, 3: 4}
1 2
3 4
2 {5: 6}
5 6
答案 6 :(得分:2)
您的问题已经得到很好的回答,但我建议使用 isinstance(d, collections.Mapping)
而不是 isinstance(d, dict)
。它适用于 dict()
、collections.OrderedDict()
和 collections.UserDict()
。
通常正确的版本是:
def myprint(d):
for k, v in d.items():
if isinstance(v, collections.Mapping):
myprint(v)
else:
print("{0} : {1}".format(k, v))
答案 7 :(得分:1)
迭代解决方案作为替代方案:
def traverse_nested_dict(d):
iters = [d.iteritems()]
while iters:
it = iters.pop()
try:
k, v = it.next()
except StopIteration:
continue
iters.append(it)
if isinstance(v, dict):
iters.append(v.iteritems())
else:
yield k, v
d = {"a": 1, "b": 2, "c": {"d": 3, "e": {"f": 4}}}
for k, v in traverse_nested_dict(d):
print k, v
答案 8 :(得分:1)
使用基于Scharron解决方案的列表的替代解决方案
def myprint(d):
my_list = d.iteritems() if isinstance(d, dict) else enumerate(d)
for k, v in my_list:
if isinstance(v, dict) or isinstance(v, list):
myprint(v)
else:
print u"{0} : {1}".format(k, v)
答案 9 :(得分:1)
这里是Fred Foo对Python 2的回答的修改版本。在原始响应中,只输出最深层次的嵌套。如果将键输出为列表,则可以保留所有级别的键,但要引用它们,则需要引用列表列表。
这里的功能是:
def NestIter(nested):
for key, value in nested.iteritems():
if isinstance(value, collections.Mapping):
for inner_key, inner_value in NestIter(value):
yield [key, inner_key], inner_value
else:
yield [key],value
引用键:
for keys, vals in mynested:
print(mynested[keys[0]][keys[1][0]][keys[1][1][0]])
用于三级字典。
在访问多个密钥之前你需要知道级别的数量,并且级别的数量应该是不变的(在迭代值时可以添加一小部分脚本来检查嵌套级别的数量,但是我尚未看过这个)。
答案 10 :(得分:1)
我使用以下代码打印嵌套字典的所有值,同时考虑值可能是包含字典的列表。在将JSON文件解析为字典并需要快速检查其中的任何值是否为None
时,这对我很有用。
d = {
"user": 10,
"time": "2017-03-15T14:02:49.301000",
"metadata": [
{"foo": "bar"},
"some_string"
]
}
def print_nested(d):
if isinstance(d, dict):
for k, v in d.items():
print_nested(v)
elif hasattr(d, '__iter__') and not isinstance(d, str):
for item in d:
print_nested(item)
elif isinstance(d, str):
print(d)
else:
print(d)
print_nested(d)
输出:
10
2017-03-15T14:02:49.301000
bar
some_string
答案 11 :(得分:0)
我发现这种方法更灵活一些,在这里你只需要提供发出键值对的生成器函数,并且可以很容易地扩展到迭代列表。
def traverse(value, key=None):
if isinstance(value, dict):
for k, v in value.items():
yield from traverse(v, k)
else:
yield key, value
然后您可以编写自己的myprint
函数,然后打印这些键值对。
def myprint(d):
for k, v in traverse(d):
print(f"{k} : {v}")
测试:
myprint({
'xml': {
'config': {
'portstatus': {
'status': 'good',
},
'target': '1',
},
'port': '11',
},
})
输出:
status : good
target : 1
port : 11
我在Python 3.6上测试了这个。
答案 12 :(得分:0)
这些答案仅适用于2级子词典。有关更多信息,请尝试:
nested_dict = {'dictA': {'key_1': 'value_1', 'key_1A': 'value_1A','key_1Asub1': {'Asub1': 'Asub1_val', 'sub_subA1': {'sub_subA1_key':'sub_subA1_val'}}},
'dictB': {'key_2': 'value_2'},
1: {'key_3': 'value_3', 'key_3A': 'value_3A'}}
def print_dict(dictionary):
dictionary_array = [dictionary]
for sub_dictionary in dictionary_array:
if type(sub_dictionary) is dict:
for key, value in sub_dictionary.items():
print("key=", key)
print("value", value)
if type(value) is dict:
dictionary_array.append(value)
print_dict(nested_dict)