ME204 2026 Icon

πŸ’» Week 01, Day 02 - Lab

Teaching Python to Read Your Files

Author

Dr Jon Cardoso-Silva

Last updated

14 July 2026

πŸ₯… Learning Objectives

By the end of this lab, you should be able to: i) Tell a plain-text file from a binary file by looking at it in the terminal, ii) Store a value in a variable and reason about what Python shows and what it hides, iii) Explain the difference between running a script with python and typing in ipython, iv) Build and index a list in Python, v) Open a connection to a file, read its contents, and convert text to numbers.

⏰ Tuesday, 14 July 2026 | Either 2:00-3.30pm or 3.30-5:00pm πŸ“ Check your timetable for the location of your class

This morning you saw that data files come in different shapes, like the plain-text CSV and JSON files, and others you cannot read directly at all. This afternoon you start working with those files in Python: reading them, pulling values out, and doing something useful with what you find.

You will find all the instructions for today’s lab below. Remember to listen to your class teacher and feel free to work with the people near you.

πŸ›£οΈ Lab Roadmap

Everything you need is on the Nuvolos machine. Here is how the afternoon is shaped.

Part Activity type Focus Outcome
Part I Follow your class teacher Plain text vs binary in the terminal You can tell one from the other by looking
Part II Follow your class teacher Variables and your first script You store values and run a .py script
Part III Follow β†’ action Lists and indexing You build a list and read values out of it
Part IV Follow β†’ action Reading data from a file You open a file, read it, and convert text to numbers
Wrap-up Together Reading a whole CSV You see the tidy way with with

πŸ‘‰ NOTE: When you see πŸ’‘ TEACHING MOMENT, watch and listen: your class teacher is showing something for the whole room. When you see 🎯 Action points, it is your turn to perform an action on your own.

⚠️ Unable to access Nuvolos? Use this backup plan

If you have trouble logging into Nuvolos, you can still do today’s lab on the computer in the lab room (or your own laptop).

  1. Download today’s data files (CSV, JSON, and the boroughs map):

  1. Unzip into a practice folder so data and figures land as siblings (the same layout as /files/ on Nuvolos). On the lab PC, open Documents, create a folder named ME204 if you do not have one yet, and unzip into that folder (not into a new empty subfolder). When you are done, you should have:

    • Documents/ME204/data/london_boroughs.csv
    • Documents/ME204/data/london_boroughs.json
    • Documents/ME204/figures/london_boroughs_map.png

    On Nuvolos, unzip into /files/ instead, so those same data/ and figures/ folders appear there.

  2. Open a terminal and move into that folder:

    cd $env:USERPROFILE\Documents\ME204

    On Mac, use cd ~/Documents/ME204 instead. On Nuvolos, use cd /files.

  3. Run ls (or dir on Windows PowerShell) and confirm you see both data and figures. Then continue Part I with the same paths as on Nuvolos (cat data/london_boroughs.csv, and so on).

  4. Tell your class teacher you are on the backup plan so they can check you are in the right place.

πŸ§ͺ Part I: What is inside a file? (12 min)

Before Python, a quick question: what is inside the files you have been given? You will look at two of them in the terminal, one that reads clearly and one that does not.

Look at a plain-text file, then a binary one

Your class teacher will open two files in the terminal: one that can be read as pure text (the CSV) and another (a PNG image) that comes out as gibberish. The idea is to understand that some files store their data as plain text you can read and edit directly, while others are binary and only make sense to the right piece of software. Follow along on your own screen as they go.

🎯 Action points

  1. Make sure you are in /files/, then show the CSV on screen:

    cat data/london_boroughs.csv
  2. Open the same file in the editor to scroll through it:

    nano data/london_boroughs.csv

    Close nano again with Ctrl+X when you are done looking.

  3. Now try the image the same way:

    cat figures/london_boroughs_map.png
  4. Come back to the whole-room discussion below.

What makes the first file a plain-text file? And when the image fills the screen with gibberish, what kind of file is it, and what would you normally open it with?

πŸ”Ž What are the commas and line breaks doing in the CSV?

Each line is one borough. The commas separate the values within that line, one value per column. This is why it is called comma-separated values. It reads as a table to you, and Python can read it the same way once you tell it where the commas and line breaks are.

βš™οΈ Part II: Variables and your first script (28 min)

Adding up 33 numbers by hand is nobody’s idea of fun, so let Python do it. First you need a way to hold a value and give it a name, and then a way to save your work in a file you can run again.

With the population CSV still on the screen: if you wanted the total population of all of London, how would you work it out by hand?

Storing a value under a name

Manual arithmetic across 33 boroughs is slow and error-prone, so your class teacher will show you how Python holds a value for you in a variable. Pay attention to when Python shows something back and when it shows nothing, because that is what tells you whether a value has just been stored or is being displayed. You will type each line yourself, right after they do.

🎯 Action points

Open ipython from /files/, then type each line and press Enter, following your class teacher:

  1. Type the population of one London borough on its own, for example 218869 for Barking and Dagenham. Python shows the number straight back to you.
  2. Now store it under a name: type pop = 218869. This time nothing shows. Why?
  3. Type pop on its own. The value you stored comes back.
  4. Add two borough populations: type 218869 + 389344. Python shows the sum.
  5. Store that sum instead: type pop = 218869 + 389344. Nothing shows again.
  6. Type pop on its own. The value has changed.

Now turn that into a script:

  1. Leave ipython by typing:

    exit
  2. Create a script with nano that stores the same sum in pop (your class teacher will show the lines):

    nano scripts/basics.py
  3. Read your file back, then run it from /files/:

    cat scripts/basics.py
    python scripts/basics.py
  4. Open the script again with nano, wrap the value in print(), save, and run it once more. Now you see the answer.

Before you run this last line, what do you think it will do? Try it once you have said your guess.

print(pop = 218869 + 389344)

Putting a variable inside a sentence

You can print a value on its own with print(pop), but often you want it inside a sentence. Python’s f-strings do this: put an f before the opening quote, and anything inside {} is replaced by its value.

🎯 Action points

  1. Try both ways of printing pop inside a sentence:

    print("The total population is", pop)
    print(f"The total population is {pop}")

    The first uses a comma to give print two arguments. The second puts pop right inside the string. Both give the same output.

  2. Now try it without the f:

    print("The total population is {pop}")

    Without the f, the braces print as literal text. This is a common mistake and worth seeing once so you recognise it later.

πŸ“Š Part III: Lists and indexing (18 min)

One number in one variable is a start, but you usually have many values to keep together. A list does that, and this part is about building one and reading the values inside it.

A list holds many values in order

A single population in a variable is useful, but real data comes as many values at once. Your class teacher will show how a list holds them together, and how you reach any one of them by its position. Follow along in ipython and try each line yourself.

🎯 Action points

Type these into ipython one line at a time, following your class teacher, so you see what each one does:

  1. Build a list of the first five borough populations:

    pop_list = [8583, 218869, 389344, 246472, 339816]
  2. Read out the first value (counting starts at zero), then the last, then the second:

    pop_list[0]
    pop_list[-1]
    pop_list[1]
  3. Add the first two values together:

    pop_list[0] + pop_list[1]
  4. Add another number to the end of the list, then look at the list again. The number below is Bromley, the next borough in the data:

    pop_list.append(329992)
    pop_list

What type is pop_list as a whole? And what type is one value inside it? How would you check, instead of guessing?

⭐ Finished early? Try this bonus

Create a script that builds a list of populations and prints it:

nano scripts/lists.py

Then run it from /files/ to see the values on screen:

python scripts/lists.py

πŸ“‚ Part IV: Reading data from a file (22 min)

This part is about how Python connects to a file, and a few surprises that catch everyone the first time.

Keep data in a file, then read it back

Typing numbers into ipython by hand does not scale, so it is better to keep data in a file and have Python read it. Your class teacher will show how Python opens a connection to a file, reads it, and closes it, and what surprises happen along the way. You will make your own small data file first, then work through the reading steps together.

🎯 Action points: open, read, close

  1. Make sure you are in /files/, then create a small data file and type a few population values into it, one per line, then save and exit:

    pwd
    nano data/london_pop.txt
  2. Open ipython from /files/.

  3. Open a connection to the file:

    f = open('data/london_pop.txt', mode='r')
  4. Read its contents:

    f.read()
  5. Close the connection, then try to read again:

    f.close()
    f.read()

    Read the error your class teacher explains.

πŸ”Ž What is that \n?

The \n you can see is a single character, not a backslash followed by an n. It marks the end of a line. When you typed each population on its own line in nano and pressed Enter, Python stored an invisible \n at the end of each one. That is why the text you read back has them running through it.

🎯 Action points: the file is read once

  1. Open the file again and read it, to confirm the values all come back:

    f = open('data/london_pop.txt', mode='r')
    f.read()
  2. Now, without reopening, read a second time:

    f.read()

The second read gives you an empty string. No error, and no data either. Where did the data go?

  1. Reopen once more so the content is fresh again:

    f = open('data/london_pop.txt', mode='r')

🎯 Action points: from text to numbers

  1. Split the contents into separate values and keep them in a variable:

    f = open('data/london_pop.txt', mode='r')
    values = f.read().split()
    values
  2. Read out the first two values and add them:

    values[0]
    values[1]
    values[0] + values[1]

The answer is far bigger than any real total. Why? What has Python done with values[0] and values[1]?

  1. Convert to numbers and add again:

    int(values[0]) + int(values[1])
  2. Now put that result inside a sentence using an f-string:

    print(f"The first two boroughs have {int(values[0]) + int(values[1])} people")

    The expression inside {} can be any Python expression, not just a variable name.

✨ Wrap-up: the tidy way (10 min)

Reading a whole CSV with with

Your class teacher will walk through, line by line, how to read a full CSV into Python using the with block, so you collect the values you care about without opening and closing the connection yourself.

πŸ“„ Reading the CSV the way you just read your file

The with block opens the connection, reads the file, and closes it for you when the block ends.

with open('data/london_boroughs.csv', mode='r') as f:
    lines = f.read().split('\n')

print(lines)

Check how many rows you got:

len(lines)

You will see 34 or 35, depending on whether there is a final empty line at the end of the file. Either way, the first row holds the column names, so the borough data starts at lines[1].

Split that first borough row on its commas and keep the result:

fields = lines[1].split(',')

In this row, fields[0] is the borough code, fields[1] the name, and fields[2] the population, still as text. Press Enter after each line to read the fields by position:

fields[1]
fields[2]

Now for row 2:

fields = lines[2].split(',')
fields[1]
fields[2]
πŸ“„ Collecting each column into its own list

Splitting one row at a time is fine, but usually you want a whole column at once. Here you keep two lists, one for borough names and one for populations, and add to them row by row. A for loop repeats the same steps for each row in turn. For every row after the header, it splits the row on commas, then adds the borough name and population to their lists.

boroughs = []
populations = []

with open('data/london_boroughs.csv', mode='r') as f:
    # splitlines() is like split('\n'), but it does not leave
    # an empty last item when the file ends with a line break
    lines = f.read().splitlines()

for row in lines[1:]:
    fields = row.split(',')
    boroughs.append(fields[1])
    populations.append(fields[2])

print(boroughs)
print(populations)

To think about: what would this look like as a dictionary instead of two separate lists?


πŸ“Ž Appendix

Data files (on Nuvolos)

  • data/london_boroughs.csv
  • data/london_boroughs.json (same data as JSON, kept for reference only and unused today)
  • figures/london_boroughs_map.png

Source: ONS Census 2021 TS001. Map source: ONS Open Geography Portal.

Command cheat sheet

Command What it does
cat file Prints a file to the screen
nano file Opens a file in the text editor
ipython Starts Python in the terminal for quick exploration
python script.py Runs a Python script
type( object ) Returns the data type of an object
some_list .append( value ) Adds a value to the end of some_list
open( path , mode='r') Returns a connection to a file, open for reading
f .read() Returns the contents of an open file f as text
f .close() Closes the connection f
int( text ) Returns text converted to a whole number