← Teacher guide

Rows of data

Students read music.csv into a list of dictionaries with csv.DictReader, find values by row and key, learn that every value from a CSV is text, then filter and count rows and build a genre finder.

Data detective · Reading data · about 50 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict and Run 10 min · Investigate 15 min · Modify 15 min · Make 10 min

Before class

Read the unit primer first. This course runs in the Python playground (real Python in the browser, Pyodide). The first load takes a few seconds; before teaching it, open the site's Check your school page once on a student device at school. music.csv appears in each student's Files tab by itself (the Files tab can put the lesson's copy back, or add a CSV from the computer). csv.DictReader(f) reads the first line as column names and makes every other line a dictionary; list(...) keeps them all. Every value is text, so "2013" + "1" is "20131" (the Predict) and comparing a year with a number fails (the bug task) until int() changes it. Dictionaries are introduced here only as far as reading one (song["title"]: a value looked up by its key); Deeper Python goes further. with open(...) is a recipe here (copy the lines), taught properly in Deeper Python's Save the game.

Running the lesson

  1. Predict: write "2013" + "1" on the board, then 2013 + 1. Quotes make text.
  2. Run: have students open music.csv in the Files tab and match the first row with songs[0].
  3. Investigate: count from 0 together: songs[0] is the first song.
  4. Modify: the count goes up inside the if; the print goes after the loop.
  5. Make: test with pop, Pop and a genre that is not there.

The hard part (on purpose)

The bug task and the first Modify: realising every value is text. Ask students to print one value with type() and predict before fixing.

When students get stuck

What you will seeA question to askThe fix
TypeError: '>=' not supported between instances of 'str' and 'int'.Is the year text or a number at this point?int(song["year"]) >= 2010.
KeyError: 'Genre'.How is the key spelled in the first line of the file?Keys must match exactly, including capitals: genre, not Genre.
The count prints once for every song.Is the print indented inside the loop?Move the print to after the loop, not indented.
FileNotFoundError: music.csv.Is music.csv in the Files tab?Use "Get this lesson's files again" in the Files tab.

Answers to the checks

  1. Predict: What does it print?
    20131. "2013" is in quotes, so it is text, and + joins text. Values read from a CSV file are all text like this.
  2. One row: What is songs[0]?
    A dictionary: the first song, with keys title, artist, year, genre and minutes
    DictReader uses the first line of the file as the keys, so every row after it becomes a dictionary like {"title": "Jolene", "artist": "Dolly Parton", ...}.
  3. Finding a value: How would you get the artist of the third song?
    songs[2]["artist"]
    songs[2] is the third song (counting from 0), and ["artist"] looks up that key in it.
  4. Spot the bug: This should list the songs from 2020 on, but it stops with TypeError: '>=' not supported between instances of 'str' and 'int'. Click the line that is wrong.
    line 7
    song["year"] is text, such as "2021", and Python will not compare text with a number. int(song["year"]) >= 2020 turns it into a number first.
  5. Where this leads: Your teacher gives you films.csv with the columns title, studio, year, rating. What would you change in your genre finder?
    The file name and the keys, such as "studio" instead of "genre"
    The program is the same shape for any table: read the rows, loop, pick by a key. Only the file and the keys change.

Solutions

One possible solution for each task. Other correct programs are fine.

Modify › Songs from 2010 on

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

print(str(len(songs)) + " songs")
print(songs[0])
for song in songs:
    if int(song["year"]) >= 2010:
        print(song["title"] + " by " + song["artist"])

Modify › How many pop songs?

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

count = 0
for song in songs:
    if song["genre"] == "pop":
        count = count + 1
print(str(count) + " pop songs")

a genre finder

import csv

with open("music.csv") as f:
    songs = list(csv.DictReader(f))

genre = input("Which genre? ").strip()
count = 0
for song in songs:
    if song["genre"].lower() == genre.lower():
        print(song["title"] + " (" + song["year"] + ")")
        count = count + 1
print(str(count) + " " + genre + " songs")

Stretch and support

Stretch: Ask for a year as well, and list only that genre's songs from that year on.

Support: Give students the loop with the if already written, and ask them only to add the count.

Exit ticket

Why does int(song["year"]) need int()?

Every value read from a CSV is text; int() turns "2013" into the number 2013 so it can be compared or added.

What each step is for

Where it leads

Next lesson: totals, averages and the longest song. Swapping in another CSV with the same idea (a class survey, sports results) keeps every program working with new keys.