4m1nh4j1
4m1nh4j1

Reputation: 4356

Reading a json file and encoding problems

I would like to parse a JSON file and print source in this code fragment :

{
        "trailers": {
            "quicktime": [], 
            "youtube": [
                {
                    "source": "mmNhzU6ySL8", 
                    "type": "Trailer", 
                    "name": "Trailer 1", 
                    "size": "HD"
                }, 
                {
                    "source": "CPTIgILtna8", 
                    "type": "Trailer", 
                    "name": "Trailer 2", 
                    "size": "Standard"
                }
            ], 
            "id": 27205
        }, 

I wrote this code :

for item in j:        
        if item['trailers']:
            e = item['trailers']
            for k,value in e.iteritems():
                if k == "youtube":
                    for innerk, innerv in k.iteritems():
                        if innerk == "source" :
                            print innerv

unfortunately I can't resolve this error :

for innerk, innerv in k.iteritems():

AttributeError: 'unicode' object has no attribute 'iteritems'

Upvotes: 3

Views: 8501

Answers (2)

ely
ely

Reputation: 77504

Assuming the JSON is formatted properly, the problem is that your code includes this check:

if k == "youtube":
    for innerk, innerv in k.iteritems():

Given that you just asked for k to be "youtube" (an instance of str or unicode), it won't make sense to expect k to have an iteritems method.

I believe instead you are expecting the associated dict that would have come along with k, something like this:

if k == "youtube":
    for innerk, innerv in value.iteritems():

I'm noticing from your JSON, though, that it looks like you should expect multiple dict variables to be loaded as the list-typed value for the case when k == "youtube". In that case, you'll need to iterate over those elements first, asking for each one's iteritems separately:

if k == "youtube":
    for each_dict in value:
        for innerk, innerv in each_dict.iteritems():

or something along those lines. The final full code would be:

for item in j:        
    if item['trailers']:
        e = item['trailers']
        for k,value in e.iteritems():
            if k == "youtube":
                for each_dict in value:
                    for innerk, innerv in each_dict.iteritems():
                        if innerk == "source" :
                            print innerv

Aside from the first-order question, you should also take a look at the dict type's built-in method get, which allows you to safely get items from a dictionary and handle the case when they are missing gracefully. In your code, when you say if item['trailers']: this may not behave the way you expect.

First, if trailers is not a key to the dictionary, it will generate a KeyError instead of just skipping that conditional block. Secondly, if the value stored for the key value trailers evaluates to False in a bool context, the conditional block will also be skipped, even if you had wanted to handle it differently (for example, suppose that None is a sentinel value signaling that there is no data for trailers in that case, but it's due to a specific error that you want to log.

Meanwhile, if it's just an empty dict then that does mean you should simply skip the conditional block). This may not matter much in one-off data exploration, but in general it's good to become automatically conditioned to avoid these sorts of pitfalls, especially when the built-in types themselves make it very easy to handle things more gracefully.

Given all of this, a more Pythonic approach might be as follows:

for item in j:    
    y_tube = item.get('trailers', {}).get("youtube", [])
    for each_dict in y_tube:
        print each_dict.get("source", "Warning: no entry found for 'source'")

Upvotes: 7

inspectorG4dget
inspectorG4dget

Reputation: 114035

Look at this line:

for k,value in e.iteritems()

So clearly, k is a key (a unicode string in your case). You clearly know this, with your comparison of if k == "youtube".
Unicode strings don't have the iteritems() method.

I have a feeling that what you're looking for is this:

for k,value in e.iteritems()
    for innerk,innerv in value.iteritems():
        # do stuff

Upvotes: 2

Related Questions