解析深层嵌套Python字典/元组

时间:2015-06-18 20:11:00

标签: python

我试图解析/循环一个深层嵌套的字典/元组,如下所示:

#!/usr/bin/env python

movies = {
    'in_bruges': {
        'display': 'In Bruges',
        'actors': {
            'Colin Farrel': {
                'age': '99',
                'height': '160'
            },
            'Brendan Gleeson': {
                'age': '88',
                'height': '158'
            }
            # many more...
        }
    },
    'fargo': {
        'display': 'Fargo',
        'actors': {
            'William H. Macy': {
                'age': '109',
                'height': '120'
            },
            'Steve Buscemi': {
                'age': '11',
                'height': '118'
            }
            # many more...
        }
    }
    # many more...
}

我可以很好地访问各个字段:

print(movies['in_bruges']['actors']['Brendan Gleeson']['age']);
88

但是我很难完成整个事情。这就是我到目前为止......

for movie, val in movies.iteritems():
    print movie
    for v in val.values():
        print v
        for x in v.values():  # <-- BREAKS HERE
            print x

错误:

AttributeError: 'str' object has no attribute 'values'

我明白为什么它会破裂......只是不确定如何解决它。此外,也许更重要的是,有更好的方法吗?这是字典和元组的混合(如果我错了,请纠正我)。我应该采用不同的结构吗?或者完全使用不同的方法?我宁愿不从csv或文本中读取它......

3 个答案:

答案 0 :(得分:2)

只需在访问values / value之前添加类型检查:

isinstance(v, dict)

isinstance(v, basestring)

代码将是:

for movie, val in movies.iteritems():
    print movie
    for v in val.values():
        if isinstance(v, dict):
            for x in v.values():
                print x
        elif isinstance(v, basestring):
            print v

答案 1 :(得分:1)

并非所有的价值观都是字典;一些是字符串:

# ...
'in_bruges': {
    'display': 'In Bruges',
    'actors': {
        # ...

那是一个字符串和一本字典。您必须改变您的处理方式:

for movie, val in movies.iteritems():
    print movie
    for v in val.values():
        if hasattr(v, 'values'):
            for x in v.values():
                print x
        else:
            print v

这里我使用了 ducktyping ;检查我想要使用的方法,而不是类型;如果它存在,我们假设它可以被视为字典。您也可以使用isinstance(v, dict),但上述内容更灵活,因为它允许使用正确方法处理任何内容。

您可以使用递归来处理任意深度的任意值:

def print_dictionary(d, indent=0):
    try:
        for k, v in d.iteritems():
            print (indent * '  '), k, '->'
            print_dictionary(v, indent + 1)
    except AttributeError:
        print (indent * '  '), d

这里我使用了异常处理;如果dict.iteritems()方法不存在,则会引发AttributeError。这种技术称为在你跳跃之前看

使用您的演示词典输出:

>>> print_dictionary(movies)
 fargo ->
   actors ->
     William H. Macy ->
       age ->
         109
       height ->
         120
     Steve Buscemi ->
       age ->
         11
       height ->
         118
   display ->
     Fargo
 in_bruges ->
   actors ->
     Brendan Gleeson ->
       age ->
         88
       height ->
         158
     Colin Farrel ->
       age ->
         99
       height ->
         160
   display ->
     In Bruges

答案 2 :(得分:1)

# for all movies
for movie, movie_details in movies.iteritems(): 
    print movie
    display = movie_details['display']
    print display

    # for all actors in this movie
    for actor,actor_details in movie_details['actors'].iteritems():
        print actor
        print actor_details['age']
        print actor_details['height']