Python Arena
Step 3 of 5

Lines with several values

Often each line of a file holds several pieces of data about one thing: a name, an age and a city, say. A common format for this is CSV, short for comma-separated values. Each line is one record, and a separator character, usually a comma , or a semicolon ;, separates its fields. Spreadsheet programs can save and open CSV files, which makes them a common way to move data from one program to another.

Splitting a string

To get the fields of a line, use the string method split, which you have met in the module on strings and lists. It cuts a string at each separator and returns the pieces as a list of strings. You give it the separator as a string:

In the Python interpreter
>>> "Rex;dog;4".split(";")
['Rex', 'dog', '4']
>>> "red,green,blue".split(",")
['red', 'green', 'blue']
>>> parts = "Rex;dog;4".split(";")
>>> parts[0]
'Rex'
>>> int(parts[2]) + 1
5
>>> "cats  and   dogs".split()
['cats', 'and', 'dogs']

The separator itself isn't in any of the pieces. The pieces are always strings, even when they look like numbers: convert them with int or float before you calculate with them. (And remember that without an argument, split() splits at spaces, however many there are in a row.)

A CSV file, line by line

The file pets.csv
Rex;dog;4
Misty;cat;11
Bubbles;fish;1
with open("pets.csv") as file:
    for line in file:
        parts = line.strip().split(";")
        name = parts[0]
        animal = parts[1]
        age = int(parts[2])
        if age >= 10:
            print(f"{name} the {animal} is a senior, {age} years old")
        else:
            print(f"{name} the {animal} is {age} years old")
Output
Rex the dog is 4 years old
Misty the cat is a senior, 11 years old
Bubbles the fish is 1 years old

line.strip().split(";") first removes the line break and then splits. Without the strip, the last field would keep the line break, ['Rex', 'dog', '4\n']. int happens to accept that, but a text field at the end of the line, such as a city, would carry its \n into everything you do with it.

Headers and extra spaces

Many CSV files start with a header line that names the columns, and some have a space after each separator. In this file each line has a player, a team and the points from any number of rounds:

The file rounds.csv
player; team; round 1; round 2; round 3
Maya; Owls; 12; 9; 15
Leo; Foxes; 8; 14; 10
with open("rounds.csv") as file:
    for line in file:
        parts = line.split(";")
        if parts[0] == "player":
            continue
        name = parts[0]
        team = parts[1].strip()
        points = []
        for part in parts[2:]:
            points.append(int(part))
        print(f"{name} ({team}): {points}, total {sum(points)}")
Output
Maya (Owls): [12, 9, 15], total 36
Leo (Foxes): [8, 14, 10], total 32
  • The header is recognized by its first field and skipped with continue.
  • parts[1] is " Owls" with a space in front, so it gets its own strip().
  • The numbers need no stripping, because int ignores spaces and a line break around a number.
  • The slice parts[2:] is every field from the third one on, so the same code works however many rounds a line has.

Your task

Challenge 1 of 3

Each line of the file orders.csv has a customer, a number of items and the price of one item. Fill in the blanks so the program prints what each customer pays. With this file

Ada;3;2.50
Ben;1;4.20
Cleo;2;3.75

the program prints:

Ada pays 7.50
Ben pays 4.20
Cleo pays 7.50

Challenge 2

What does this program print? Type each line it prints.

Challenge 3

The file menu.csv lists the dishes of a café after a header line. Each line has a dish, its price and its course: starter, main or dessert. Write a function prices_in(filename, course) that returns a dictionary of the dishes of the given course only. Its keys are the dishes, and its values are their prices as decimal numbers (float). When the menu has no dishes of that course, the dictionary is empty.

With this file

dish;price;course
soup;6.50;starter
pasta;11.90;main
salad;8.00;starter
cake;5.20;dessert

print(prices_in("menu.csv", "starter")) prints:

{'soup': 6.5, 'salad': 8.0}