Nesting: A List of Dictionaries
Real data is rarely a single list or a single dictionary. It is a list of records, where each record is a dictionary with the same keys: a row of a spreadsheet, a contact in an address book, an order in a shop. This shape is so common that once you can read it, you can read most of what files and the internet will hand you.
Think of a stack of identical index cards. Every card has the same printed headings, name, city and age, and each card is filled in differently. The stack is the list; each card is a dictionary.
Records
A record describes one thing with named fields. In Python, a dictionary does this naturally: {"name": "Anna", "city": "Lisbon", "age": 34}. The keys are the headings on the card, and the values are what is written under them.
A List of Records
Put several records in a list and you have a small table. Walk it with a for loop and read one field from each record: here, every person's name and city.
people = [
{"name": "Anna", "city": "Lisbon", "age": 34},
{"name": "Omar", "city": "Leeds", "age": 29},
{"name": "Lena", "city": "Lisbon", "age": 41},
]
for person in people:
print(person["name"], "lives in", person["city"])
Anna lives in Lisbon Omar lives in Leeds Lena lives in Lisbon
Reaching Inside
To reach one value directly, chain the brackets and read them left to right. people[1] is the second record, Omar's card; people[1]["city"] is the city on that card, Leeds. The common mistake is to skip the first step: people["city"] asks the list for a key, and lists do not have keys, so Python raises a TypeError saying list indices must be integers.
>>> people = [{"city": "Lisbon"}, {"city": "Leeds"}]
>>> people[1]["city"]
'Leeds'
>>> people["city"]
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
people["city"]
~~~~~~^^^^^^^^
TypeError: list indices must be integers or slices, not str
Filtering and Summarising
The patterns you already know combine without anything new. To find everyone in one city, loop and keep the records that match; a comprehension does it in one line. To average an age, total it with sum over the ages and divide by the count.
people = [
{"name": "Anna", "city": "Lisbon", "age": 34},
{"name": "Omar", "city": "Leeds", "age": 29},
{"name": "Lena", "city": "Lisbon", "age": 41},
]
in_lisbon = [p["name"] for p in people if p["city"] == "Lisbon"]
print(in_lisbon)
average_age = sum(p["age"] for p in people) / len(people)
print(f"Average age: {average_age:.1f}")
['Anna', 'Lena'] Average age: 34.7
The second line inside sum has no square brackets: Python lets you feed a comprehension straight into a function like this, without building a list first. Read it the same way: each person's age, for every person.
A First Look at JSON
The same data, written out as text for another program to read, looks almost identical. The json module turns a list of dictionaries into JSON, the text format most of the internet uses to exchange data. Chapter 10 uses it properly; for now, notice how little changes: the same brackets, braces, keys and values.
import json people = [{"name": "Anna", "city": "Lisbon"}, {"name": "Omar", "city": "Leeds"}] print(json.dumps(people, indent=2))
[
{
"name": "Anna",
"city": "Lisbon"
},
{
"name": "Omar",
"city": "Leeds"
}
]
- "
people["city"]gives every city." people is a list, and lists are reached by position. Pick a record first, or loop over them. - "Every record always has every key." It should, but real data is messy. get with a default copes with a record that is missing a field.
- "Nested data needs special tools." It is lists and dictionaries all the way down; everything on this page uses tools you already had.
- Spreadsheet rows in Chapter 7 and answers from the internet in Chapter 10 both arrive in exactly this shape.
- Reading a chain like
data[0]["name"]fluently is a skill used in every chapter from here on.
Knowledge Check
What does people[1]["city"] give for the list on this page?
- The city of the first person, Anna
- The city of the second person, Omar
- Every city from the list, one after another
- A TypeError, because the brackets cannot be chained
Why does people["city"] fail?
- Because the key city is missing from every record
- Because city has to be written without quotes
- Because people is a list, which needs a position, not a key
- Because a list of dictionaries cannot be read at all
What does [p["name"] for p in people if p["city"] == "Lisbon"] produce?
- A list of the names of people whose city is Lisbon
- The number of people whose city is Lisbon
- The full records of the people who live in Lisbon
- True if anyone in the list lives in Lisbon
What does json.dumps do with a list of dictionaries?
- Saves the list into a file on the disk
- Sends the list to a server somewhere on the internet
- Checks the list for errors and removes bad records
- Turns it into JSON text with the same structure
You got correct