遍历所有嵌套字典值?

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) 

完整的testing案例

字典:

 {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'} 

正如Niklas所说,你需要recursion,即你想定义一个函数来打印你的字典,如果这个值是一个字典,你想使用这个新的字典调用你的打印function。

就像是 :

 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)) 

由于dict是可迭代的,因此您可以将经典的嵌套容器迭代公式应用于此问题,只需稍作更改即可。 这是一个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 

testing:

 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中,可以创build一个自定义的Mapping ,该Mapping具有Mapping资格但不包含iteritems ,在这种情况下,这将失败。 文档没有指出它需要一个Mapping iteritems ; 另一方面, 源给出了Mappingtypes的一个iteritems方法。 因此,对于自定义Mappings ,从collections.Mappinginheritance,以防万一。

在Python 3中,有一些改进要做。 从Python 3.3开始,抽象基类生活在collections.abc 。 为了向后兼容,它们仍然保留在collections ,但更好的是将我们的抽象基类放在一个名称空间中。 所以这从collectionsimportabc 。 Python 3.3也增加了yield from ,这是为这种情况而devise的。 这不是空的句法糖; 它可能会导致更快的代码和与协程的更明智的交互。

 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 

替代迭代解决scheme:

 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)) 

如果你编写你自己的recursion实现或者迭代等价的堆栈,有潜在的问题 。 看到这个例子:

  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 

在正常的意义上,嵌套字典将是一个像数据结构一样的十字树。 但是这个定义并不排除一个交叉边缘甚至一个后边缘的可能性(因此不再是一棵树)。 例如,这里key2.2对于来自key1的字典有效, key2.3指向整个字典(后沿/循环)。 当存在后沿(循环)时,堆栈/recursion将无限运行。

  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.iteritems(): 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 = d.items() while stack: k, v = stack.pop() if isinstance(v, dict): stack.extend(v.iteritems()) else: print("%s: %s" % (k, v)) 

但是,Python实际上在嵌套字典中检测循环:

  print dic {'key2': {'key2.1': 'value2', 'key2.3': {...}, 'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}} 

“{…}”是检测周期的地方。

这是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 

我写的略有不同的版本,logging沿途的钥匙到达那里

 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' 

如果你需要这种方式,修改它以跟踪前缀为键的元组而不是string也很容易。

迭代解决scheme:

 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 

这里是Fred Foo对Python 2的答案的修改版本。在原始响应中,只输出最深层次的嵌套。 如果将键作为列表输出,则可以保留所有级别的键,但要引用它们则需要引用列表的列表。

这个function:

 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]]) 

为三级字典。

您需要知道访问多个键之前的级别数量,级别数量应该是常数(在遍历值时,可能会添加一小段脚本来检查嵌套级别的数量,但是我没有但看着这个)。

基于Scharron解决scheme使用列表的另一种解决scheme

 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)