简体   繁体   中英

Accessing a list contained in a JSON object with Python

testVar = {
  "date": 1520053431,
  "location": {
  "lat": 39.349887,
  "lng": -82.116147
  },
  "items": [
    {
      "macAddress": "98:90:96:9C:94:6C",
      "manufacturer": "intel"
    },
    {
  "macAddress": "98:90:96:9C:94:52",
  "manufacturer": "intel"
    },
    {
      "macAddress": "98:90:96:90:94:52",
      "manufacturer": "intel"
    }
  ]
}

print(testVar.items[0])

I have this JSON object, and I'm trying to access the items list, but this produces the error:

TypeError: 'builtin_function_or_method' object is not subscriptable

I tried parsing it with json.loads and json.dumps but neither of those worked either.

Let me present a very simple example first, since this is going to be very useful for us later on. Imagine I have this simple function:

def myFunc():
    return [1,2,3]

Question: What is the first element of myFunc ? In other terms, what is myFunc[0] . Be careful, I am not asking the first element of the output of it, ie myFunc()[0] ; my question is the first element of myFunc itself! The former would be the first element of [1,2,3] , which is 1 ; but the latter will give me a TypeError , because a function can't be subscripted; akin to the fact that a recipe can produce delicious food, but you can't eat the recipe itself.

Let's take a look at your error message:

TypeError: 'builtin_function_or_method' object is not subscriptable

This means that you are somehow trying to subscript a 'builtin_function_or_method' object. Let's look at your code and understand what this error is due to. Luckily, your call is just one line, hence easy to debug:

testVar.items[0]

What you are doing is to reach the first element of the items function or method of a dict . Be careful, not the first element of the outcome, but the function itself. How am I so sure? Because you forgot the parentheses, therefore haven't even called the function yet, ie you didn't do testVar.items()[0] .

Let's look closer at the built-in items function of dict s. When we just run testVar.items , this is the response we get: <function items> . Let's run the following to get some help about its docstring: ?testVar.items , which returns the following:

Docstring: D.items() -> list of D's (key, value) pairs, as 2-tuples
Type:      builtin_function_or_method

A-ha! We just saw what the error message we had mentioned: builtin_function_or_method ! So the error is really due to your code not being able to call the function properly, but try to get the first element of the function itself.

Let me give a simpler but equivalent example. Say, I have a list x = [2, 3, 1] and I want to find its smallest element. I can use the built-in function of sort , and then get the first element in the sorted list. Therefore the proper syntax would be x.sort()[0] but if I forget the () , and write x.sort[0] I will be trying to get the first element of not the result of the sort function (because I didn't even call it to get a result!) but the first element of the function itself. Remember the recipe not being edible? Same thing.

In summary: A function can return an iterable which you can subscript, but a function itself is not subscriptable.

Let's play around with this function a little bit. Let's iterate on it as (key, value) pairs per docstring:

for k, v in testVar.items():
    print k, v
# Result:
date 1520053431
items [{'macAddress': '98:90:96:9C:94:6C', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:9C:94:52', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:90:94:52', 'manufacturer': 'intel'}]
location {'lat': 39.349887, 'lng': -82.116147}

This makes sense, because we indeed have 3 keys and corresponding 3 values.

Now, how can you get the values corresponding to the key named items ? Notice, this is one of your three keys, but has the same name as the built-in function of dict s we discussed above. This is where your confusion is coming from.

The error message was due to the items function, let's discuss how to get the value corresponding to the key named items . One inefficient way is using the loop syntax I presented above:

for k, v in testVar.items():
    if k == 'items':
        print v
# Result:
[{'macAddress': '98:90:96:9C:94:6C', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:9C:94:52', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:90:94:52', 'manufacturer': 'intel'}]

There you go, here is your items ! A second and efficient way of doing the same thing is calling the key name, and the values will be returned to us:

testVar['items']
# Result: 
[{'macAddress': '98:90:96:9C:94:6C', 'manufacturer': 'intel'},
 {'macAddress': '98:90:96:9C:94:52', 'manufacturer': 'intel'},
 {'macAddress': '98:90:96:90:94:52', 'manufacturer': 'intel'}]

To wrap-up:

  1. Pay attention to the cases where your key in a dict has the same name of a built-in function or method.
  2. You can't do myDict.key , but myDict['key'] .
  3. You can also loop over the item function of dict s as (key, value) pairs and get the value corresponding to the key. But don't do this, this is inefficient compared to the constant time complexity of myDict['key'] .
  4. If you are calling myDict.function , make sure you actually put that function into action by myDict.function() . That is, don't eat the recipe, but eat what it produces.

As it has curly brackets ( {...} ), it's stored in a dict (ionary). This means you can't use the dot operator ( . ) to access the data inside.

As it's a dict , you also can't access it like a list . Instead, you need to use the keys available (the strings before the colons).

In this case, you need to do something like textVar['items'] to access the 'items' list .

testVar is a dictionary and dictionaries in Python have the items() method. For instance, in order to access all key/value pairs in this dictionary, you would use, according to Python docs . Notice the items() method below.

for key, value in testVar.items():
      print(key, value)

As pointed out by @FatihAkici, the statement testVar.items()[0] is syntactically incorrect in that you are trying to call the items() method which does not support indexing. This means that you cannot access items within the object by index positions, like we do in lists:

Accessing a list by index position:

music = ['Beatles', 'Led Zeppelin', 'The Doors']
#item at index 0:
music[0]   #Beatles

Meanwhile, as you can see the object testVar.items() is of type dict_items and can only be accessed by key/value.

testVar.items()[0]
TypeError: 'dict_items' object does not support indexing

#Output: dict_items([('date', 1520053431), ('location', {'lat': 39.349887, 'lng': -82.116147}), ('items', [{'macAddress': '98:90:96:9C:94:6C', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:9C:94:52', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:90:94:52', 'manufacturer': 'intel'}])])

print(testVar.items())   

To access the items list, you can use list comprehensions. This is a compact way to access all items with less code:

test = [print(key, value) in testVar for key,value in testVar.items() if key=="items"]

#test: items [{'macAddress': '98:90:96:9C:94:6C', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:9C:94:52', 'manufacturer': 'intel'}, {'macAddress': '98:90:96:90:94:52', 'manufacturer': 'intel'}]

The problem is with the print statement. JSON works as same as a dictionary. so to access any element in dictionary, we use dictionary_name[key]

Therefore the below code works fine:

(change the print statement in the code as below)

print(testVar['items'][0])

You can access the wanted variable by doing this:

print(testVar["items"][0])

Because both "testVar" and "items" are dict variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM