Read a value deep inside a response
An API response is a dictionary holding lists holding more dictionaries. A chain of keys and indexes, read left to right, reaches any value inside it.
- Read a chain like
page["features"][0]["properties"]["mag"]one step at a time - Use a key on a dictionary and a position on a list, and recognise the error when you mix them up
- Write a function that pulls several values out of one nested record
The US Geological Survey publishes every earthquake as a GeoJSON record. One record is a dictionary; its properties key holds another dictionary (magnitude, place), and its geometry key holds a dictionary whose coordinates is a list: longitude, latitude, depth in km.
Nothing new is needed to read inside it. quake["properties"] gives back a dictionary, and you can put another pair of brackets straight after it: quake["properties"]["place"]. Each pair of brackets works on the value the previous pair produced, left to right.
Run each example to see what it prints. Running examples doesn't count toward progress.
quake = {
"id": "us6000pw77",
"properties": {"mag": 4.7, "place": "Arctic Ocean"},
"geometry": {"type": "Point", "coordinates": [-107.5679, 80.7069, 10]},
}
print(quake["properties"]["place"])
print(quake["properties"]["mag"])
coordinates = quake["geometry"]["coordinates"]
print(coordinates)
print("depth:", quake["geometry"]["coordinates"][2], "km")Each step must match the kind of value it lands on: a key for a dictionary, a position for a list. A page of results keeps its events in a list under features, so you need a position before you can ask for properties.
page = {"metadata": {"count": 1}, "features": [{"id": "us6000pw77", "properties": {"mag": 4.7}}]}
print(page["metadata"]["count"])
print(page["features"]["properties"]["mag"])In a program, the chain lives in a function that takes the whole response and returns just what the caller needs. Check for an empty list before you reach for position 0, because an API can return a page with no events.
def first_event(page): if len(page["features"]) == 0: return "no events" first = page["features"][0] place = first["properties"]["place"] depth = first["geometry"]["coordinates"][2] return f"{page['metadata']['count']} events; first: {place}, {depth} km deep" page = { "metadata": {"count": 2}, "features": [ {"properties": {"place": "233 km E of Levuka, Fiji"}, "geometry": {"coordinates": [-178.4779, -18.0069, 585.411]}}, {"properties": {"place": "Southern Alaska"}, "geometry": {"coordinates": [-147.2371, 61.4029, 9.6]}}, ], } print(first_event(page)) print(first_event({"metadata": {"count": 0}, "features": []}))
When to use it: any time data comes as JSON from an API or a file: orders with their lines, a user with their address, a page of search results. Mistakes to avoid: a key where a list needs a position (the TypeError above), position 0 of an empty list (IndexError), and, with GeoJSON, reading position 0 as the latitude: the format stores longitude first.
- Each pair of brackets works on the value the previous one produced: keys for dictionaries, positions for lists.
- A key on a list gives
TypeError: list indices must be integers…; position 0 of an empty list givesIndexError. - GeoJSON coordinates are longitude, latitude, depth.
- Next: real records often leave keys out.
getreads a key that might be missing.