Lists of dictionaries: real data
Every result you get back from a website, an exam system or an exported spreadsheet arrives in the same shape: many things, each described the same way. Thirty students, each with a name and a score. Twelve buses, each with a route and a departure time.
A list holds the many. A dictionary describes each one. Put them together and you have the structure almost all real data uses.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
]
print(students[0])
{'name': 'Ayesha', 'score': 88}Each dictionary in the list is called a record. The list is in order, the keys inside each record are not something you count to — you name them.
Reaching one field
students[0] gave you a whole record. To get one field out of it, add
the key in a second set of brackets.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
{"name": "Chen", "score": 90},
]
print(students[0]["name"])
print(students[1]["score"])
print(len(students))
Ayesha 74 3
len(students) counts records, not fields. Three students, however many
keys each of them has.
Reading data[0]["name"] without panicking
students[0]["name"] is where beginners stall. Two sets of brackets
next to each other look like one strange piece of syntax, so people
squint at the whole thing hoping it will resolve, and it never does.
It is not one thing. It is two ordinary steps, left to right, and Python
does them in that order. First students[0], which produces a
dictionary. Then ["name"] on that dictionary, which produces a string.
Write it out and the mystery disappears:
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
]
first = students[0]
print(first)
name = first["name"]
print(name)
{'name': 'Ayesha', 'score': 88}
Ayeshastudents[0]["name"] is exactly those two lines with the middle name
left out. Whenever a nested expression confuses you, break it apart into
named steps and print each one. You can always join it back up
afterwards.
The rule to hold on to is that the brackets belong to whatever is
immediately to their left, not to the expression as a whole. So the
first [0] is a list index, because students is a list. The second
["name"] is a dictionary key, because students[0] is a dictionary.
Get that order wrong and Python says so:
students = [
{"name": "Ayesha", "score": 88},
]
print(students["name"])
That message — list indices must be integers — is Python telling you that you tried a dictionary move on a list. Read the error as "you are one level out", and count your brackets from the left.
Looping over records
You rarely want record zero. You want all of them. A for loop over a
list of dictionaries hands you one dictionary per turn.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
{"name": "Chen", "score": 90},
]
for student in students:
print(student["name"], student["score"])
Ayesha 88 Bilal 74 Chen 90
Notice there is no [0] anywhere. Inside the loop, student is a
record already, so it only needs one set of brackets. Singular name for
the loop variable, plural for the list, and you will keep the two levels
straight without thinking about it.
An f-string reads better for anything you actually show a person. Mind the quotes: use single quotes for the key when the f-string itself uses double.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
]
for student in students:
print(f"{student['name']} scored {student['score']}")
Ayesha scored 88 Bilal scored 74
Filtering
Filtering means walking every record, testing one field, and collecting the records that pass into a new list.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
{"name": "Chen", "score": 90},
]
passed = []
for student in students:
if student["score"] >= 80:
passed.append(student)
print(passed)
print(len(passed))
[{'name': 'Ayesha', 'score': 88}, {'name': 'Chen', 'score': 90}]
2Three lines of pattern, and you will write it hundreds of times: empty
list, loop, if, append. passed is a list of dictionaries too, so
everything you have just learned works on it — passed[0]["name"] is
Ayesha.
If a key might be missing from some records, student["score"] would
crash. student.get("score", 0) gives you a fallback instead, which
matters the moment your data comes from somewhere you do not control.
Going deeper than one level
A record's value can itself be a list, or another dictionary. The rule does not change: each set of brackets applies to the thing on its left.
students = [
{"name": "Fatima", "city": "Lahore", "marks": [72, 90, 65]},
{"name": "Omar", "city": "Karachi", "marks": [88, 45, 91]},
]
print(students[1]["marks"][0])
print(len(students[0]["marks"]))
88 3
Read students[1]["marks"][0] in three beats: record 1, its marks list,
the first mark. Say it out loud in that order and the brackets stop
looking like a wall.
Counting and adding across records
Totals work the same as any other loop — a running variable outside, and one field pulled from each record inside.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
{"name": "Chen", "score": 90},
]
total = 0
for student in students:
total += student["score"]
print(total)
print(total / len(students))
252 84.0
The average prints as 84.0 rather than 84 because / in Python
always produces a float, even when the division comes out exactly.
Adding a field to every record
Here is the most useful thing in this lesson. Because the loop variable refers to the same dictionary that is sitting in the list — not a copy of it — assigning a new key inside the loop changes the real record.
students = [
{"name": "Ayesha", "score": 88},
{"name": "Bilal", "score": 74},
]
for student in students:
if student["score"] >= 80:
student["grade"] = "A"
else:
student["grade"] = "B"
print(students)
[{'name': 'Ayesha', 'score': 88, 'grade': 'A'}, {'name': 'Bilal', 'score': 74, 'grade': 'B'}]Every record now carries a grade it did not have before, and you never
touched students by index. This is the same sharing behaviour that
catches people out in the list methods
lesson — here it works entirely in your favour.
That single loop is how you enrich real data: read a raw export, walk it once, add the fields you actually need, and hand the list on to whatever draws the report.
Related reading: the dictionaries lesson for
keys, .get() and .items(), the list methods
lesson for sorting and copying, and the slicing
lesson for taking the first few records off a long
list.
Prefer learning with a teacher?
WasiLearn Academy runs small-group classes covering this material, online and in Karachi.
See the classes