Reputation: 4356
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
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
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