{"id":"data-processing-csv","slug":"csv-module","title":"The csv module","text":"In part 6 you read CSV files by splitting each line yourself. That works until a value contains the separator itself, which happens more often than you'd think. The standard library's **`csv`** module reads CSV files properly. Here is the pets file from part 6 again, read with it:\n\n```file pets.csv\nRex;dog;4\nMisty;cat;11\nBubbles;fish;1\n```\n\n```python\nimport csv\n\nwith open(\"pets.csv\") as file:\n    for row in csv.reader(file, delimiter=\";\"):\n        print(row)\n```\n\n```output\n['Rex', 'dog', '4']\n['Misty', 'cat', '11']\n['Bubbles', 'fish', '1']\n```\n\n`csv.reader(file, delimiter=\";\")` goes through the file one line at a time, and gives each line as a list of its values, already without the line break at the end, so there's nothing to strip. The **delimiter** is the character between the values. Leave it out and the reader assumes a comma: the C in CSV stands for comma, after all, although semicolons are common too.\n\n### The values are strings\n\nAs with `split`, every value is a string. Convert numbers yourself before calculating with them:\n\n```file pets.csv\nRex;dog;4\nMisty;cat;11\nBubbles;fish;1\n```\n\n```python\nimport csv\n\ntotal = 0\nwith open(\"pets.csv\") as file:\n    for row in csv.reader(file, delimiter=\";\"):\n        name = row[0]\n        age = int(row[2])\n        total += age\n        print(f\"{name} is {age}\")\nprint(\"Total age:\", total)\n```\n\n```output\nRex is 4\nMisty is 11\nBubbles is 1\nTotal age: 16\n```\n\n### Why not split?\n\nA value that contains the delimiter is put in double quotes. Spreadsheet programs do this when they save a CSV file. `split` doesn't know about quotes, but the csv module does:\n\n```file books.csv\n\"Python, the basics\",Ada Lovelace,2026\nShort stories,\"King, Stephen\",2019\n```\n\n```python\nimport csv\n\nwith open(\"books.csv\") as file:\n    for line in file:\n        print(line.strip().split(\",\"))\n\nwith open(\"books.csv\") as file:\n    for row in csv.reader(file):\n        print(row)\n```\n\n```output\n['\"Python', ' the basics\"', 'Ada Lovelace', '2026']\n['Short stories', '\"King', ' Stephen\"', '2019']\n['Python, the basics', 'Ada Lovelace', '2026']\n['Short stories', 'King, Stephen', '2019']\n```\n\nSplit cuts the titles and names in two and keeps the quotes. The reader gives three clean values per line.\n\n`csv.reader` works on anything that gives lines of text, not only on an open file. A list of strings will do, which is handy for trying it out:\n\n```pycon\n>>> import csv\n>>> lines = ['Ada;\"Lovelace; Countess\";1815']\n>>> for row in csv.reader(lines, delimiter=\";\"):\n...     print(row)\n...\n['Ada', 'Lovelace; Countess', '1815']\n```\n","task":"The file `scores.csv` has a name and a score on each line, separated by a semicolon. Fill in the blanks so the program prints each line as in the example:\n\n```text\nAda;12\nLinus;9\n```\n\n```\nAda scored 12\nLinus scored 9\n```\n","kind":"fill","seed":"import csv\n\nwith open(\"scores.csv\") as file:\n    for row in csv.[[reader]](file, delimiter=[[\";\"‖';']]):\n        print(row[0], \"scored\", row[1])\n","solution":"import csv\n\nwith open(\"scores.csv\") as file:\n    for row in csv.reader(file, delimiter=\";\"):\n        print(row[0], \"scored\", row[1])\n","hints":["The function of the `csv` module that reads the rows is the one this step is about.","Type `reader` into the first blank. The delimiter is a string of one character: `\";\"`."],"tests":[{"name":"Test 1","stdin":"","files":{"scores.csv":"Ada;12\nLinus;9\n"},"expect":"Ada scored 12\nLinus scored 9","hidden":false},{"name":"Test 2","stdin":"","files":{"scores.csv":"Grace;15\nGuido;11\nMargaret;14\n"},"expect":"Grace scored 15\nGuido scored 11\nMargaret scored 14","hidden":true}],"require":[],"forbid":[],"more":[{"task":"The file `weather.csv` has a date and the day's highest temperature on each line, separated by a semicolon. Write a program that reads it with the `csv` module and prints the warmest day and its temperature. If several days share the highest temperature, print the first of them. For example, for this file:\n\n```text\n2026-07-12;24\n2026-07-13;29\n2026-07-14;27\n```\n\nthe program prints:\n\n```\nWarmest: 2026-07-13, 29 degrees\n```\n","kind":"code","seed":"import csv\n","solution":"import csv\n\nwarmest_day = \"\"\nwarmest = 0\nfirst = True\nwith open(\"weather.csv\") as file:\n    for row in csv.reader(file, delimiter=\";\"):\n        temperature = int(row[1])\n        if first or temperature > warmest:\n            warmest_day = row[0]\n            warmest = temperature\n            first = False\nprint(f\"Warmest: {warmest_day}, {warmest} degrees\")\n","hints":["Read the rows with `csv.reader(file, delimiter=\";\")`. The date is `row[0]` and the temperature `int(row[1])`.","Keep the best day so far and its temperature in two variables, and replace them when a row is warmer.","Temperatures can be below zero, so don't start the best temperature at 0: take the first row as the best so far."],"tests":[{"name":"Test 1","stdin":"","files":{"weather.csv":"2026-07-12;24\n2026-07-13;29\n2026-07-14;27\n"},"expect":"Warmest: 2026-07-13, 29 degrees","hidden":false},{"name":"Test 2","stdin":"","files":{"weather.csv":"2026-01-05;-12\n2026-01-06;-3\n2026-01-07;-8\n2026-01-08;-3\n"},"expect":"Warmest: 2026-01-06, -3 degrees","hidden":true},{"name":"Test 3","stdin":"","files":{"weather.csv":"2026-08-01;31\n"},"expect":"Warmest: 2026-08-01, 31 degrees","hidden":true}],"require":[{"pattern":"csv\\.reader","message":"Read the file with `csv.reader`."}],"forbid":[]},{"task":"The file `products.csv` has a product's name, its price and how many are in stock on each line, separated by commas. Some names have a comma in them, and those are in double quotes. Write a function `stock_value(filename)` that reads the file with the `csv` module and returns the total value of the stock: the sum of price times count over all the lines. For example, for this file the function returns `39.0`:\n\n```text\n\"Pencils, box of 12\",4.50,4\nEraser,0.75,8\n\"Notebook, A5\",2.50,6\n```\n","kind":"code","seed":"import csv\n\n\ndef stock_value(filename):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(stock_value(\"products.csv\"))\n","solution":"import csv\n\n\ndef stock_value(filename):\n    total = 0\n    with open(filename) as file:\n        for row in csv.reader(file):\n            total += float(row[1]) * int(row[2])\n    return total\n\n\nif __name__ == \"__main__\":\n    print(stock_value(\"products.csv\"))\n","hints":["The values are separated by commas, which is what `csv.reader` assumes, so it needs no delimiter here. It also removes the quotes around the names.","The price is a float and the count an integer: `float(row[1]) * int(row[2])`. Add it to a total, and return the total after the loop."],"tests":[{"name":"stock_value(\"products.csv\")","stdin":"","call":"stock_value(\"products.csv\")\n","files":{"products.csv":"\"Pencils, box of 12\",4.50,4\nEraser,0.75,8\n\"Notebook, A5\",2.50,6\n"},"expect":"39.0","hidden":false,"returns":true},{"name":"stock_value(\"shop.csv\")","stdin":"","call":"stock_value(\"shop.csv\")\n","files":{"shop.csv":"\"Tea, green\",3.25,4\n\"Mugs, set of 2\",12.00,1\nSpoon,1.50,2\n"},"expect":"28.0","hidden":true,"returns":true}],"require":[{"pattern":"csv\\.reader","message":"Read the file with `csv.reader`, which understands the quotes."}],"forbid":[]}]}