1

I'm trying to parse/loop through a deeply nested dictionary/tuple such as this:

#!/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...
}

I can access individual fields just fine:

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

But I'm having a hard time looping through the whole thing. This is what I have so far...

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

Error:

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

I understand why it's breaking... just not sure how to fix it. Also, and probably more importantly, is there a better way to do this? This is a mix of a dictionary and a tuple (correct me if I'm wrong). Should I structure it differently? Or use a different method altogether? I'd rather not read it in from a csv or text...

Martijn Pieters
1.1m326 gold badges4.2k silver badges3.5k bronze badges
asked Jun 18, 2015 at 20:10

3 Answers 3

2

Just add the check of type before access to values/value:

isinstance(v, dict)

or

isinstance(v, basestring)

And the code will be:

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
answered Jun 18, 2015 at 20:16
Sign up to request clarification or add additional context in comments.

Comments

1

Not all your values are dictionaries; some are strings:

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

That's a string and a dictionary. You'll have to vary your handling:

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

Here I used ducktyping; checking for a method I want to use, rather than a type; if it is present we assume it can be treated as a dictionary. You could also use isinstance(v, dict) but the above is more flexible as it allows anything with the right method to be treated the same.

You could use recursion to handle arbitrary values at any depth:

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

Here I used exception handling; if the dict.iteritems() method isn't present an AttributeError is raised. This technique is called Look Before You Leap.

With your demo dictionary this outputs:

>>> 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
answered Jun 18, 2015 at 20:17

1 Comment

Wow this is excellent! Works perfectly. Thanks so much for the thoughtful explanation, Martijn. Really appreciate it.
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']
answered Jun 18, 2015 at 20:19

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.