DEV Community

Cover image for Python Week 6: Our Programs Finally Read Real Files
Navas Herbert
Navas Herbert

Posted on

Python Week 6: Our Programs Finally Read Real Files

 Every program we'd built so far had one problem.

The moment you closed it, everything disappeared. The students we added to the registry. The scores we calculated. The transactions we analysed. Gone. You'd open the program again, and it would start from scratch.

Real software doesn't work like that. Real software reads from files, processes data, writes results back out. Real software persists.

Week 6 was the week we crossed that line.

I walked in with a file called students.csv - 30 rows of messy, real-looking student data. Names in wrong cases. Missing scores. Inconsistent course names. I put it on the projector and said: "By the end of today, Python will read this, clean it, and report on it. Without us touching a single row manually."

The room got quiet in the good way.


String Methods: Cleaning Up Messy Text

Before we touched any file, we needed sharper tools for working with text. Real data is almost always dirty - inconsistent capitalisation, rogue spaces, mixed formats.

These are the methods that fix it:

name = "  amina WAWERU  "

print(name.strip())       # remove leading/trailing spaces
print(name.lower())       # all lowercase
print(name.upper())       # all uppercase
print(name.title())       # Title Case - first letter of each word
print(name.strip().title())  # chain them together
Enter fullscreen mode Exit fullscreen mode
amina WAWERU
  amina waweru  
  AMINA WAWERU  
  Amina Waweru  
Amina Waweru
Enter fullscreen mode Exit fullscreen mode

That last line - chaining .strip() and .title() - is where students start thinking like data cleaners. One messy string in, one clean string out.

More essential methods:

course = "  data engineering "

print(course.strip())              # "data engineering"
print(course.strip().title())      # "Data Engineering"
print(course.strip().replace("engineering", "science"))  # "data science"
print("Data Engineering".startswith("Data"))    # True
print("Data Engineering".endswith("ing"))       # True
print("Data Engineering".count("a"))            # 2
print("Data Engineering".split(" "))            # ['Data', 'Engineering']
Enter fullscreen mode Exit fullscreen mode
data engineering
Data Engineering
data science
True
True
2
['Data', 'Engineering']
Enter fullscreen mode Exit fullscreen mode

The SQL connection came up again naturally. Wanjiku said: ".strip() is TRIM(). .title() is INITCAP(). We already know this."

Exactly. Different language, same ideas. This is why learning SQL first pays off.


String Checking Methods

These return True or False - perfect for validation:

score_input = "88"
name_input = "Amina123"
empty_input = "   "

print(score_input.isdigit())      # True - all digits
print(name_input.isalpha())       # False - has numbers
print(empty_input.strip() == "")  # True - effectively empty
print("amina@lux.co.ke".find("@"))  # 5 - position of @
Enter fullscreen mode Exit fullscreen mode
True
False
True
5
Enter fullscreen mode Exit fullscreen mode

We used these to write a simple input validator - the kind of check every real form needs before saving data:

def validate_student_input(name, score_str):
    errors = []

    if not name.strip():
        errors.append("Name cannot be empty")
    if not score_str.isdigit():
        errors.append("Score must be a whole number")
    elif not (0 <= int(score_str) <= 100):
        errors.append("Score must be between 0 and 100")

    return errors

# Test it
print(validate_student_input("Amina", "88"))      # []
print(validate_student_input("", "88"))            # ['Name cannot be empty']
print(validate_student_input("Brian", "abc"))      # ['Score must be a whole number']
print(validate_student_input("Njeri", "150"))      # ['Score must be between 0 and 100']
Enter fullscreen mode Exit fullscreen mode
[]
['Name cannot be empty']
['Score must be a whole number']
['Score must be between 0 and 100']
Enter fullscreen mode Exit fullscreen mode

An empty list means everything is valid. A list with items means something failed. Clean, readable, reusable - everything we learned in Week 4 (functions) and Week 5 (lists) coming together.


File Handling: Reading From the Real World

Now the main event.

Python opens files with open(). But instead of using open() directly, we use the with statement - it opens the file, lets you work with it, and automatically closes it when you're done. No risk of leaving files hanging open.

with open("greeting.txt", "r") as file:
    content = file.read()
    print(content)
Enter fullscreen mode Exit fullscreen mode

The modes:

  • "r" — read (file must exist)
  • "w" — write (creates file, overwrites if it exists)
  • "a" — append (adds to the end without deleting)

Writing a file:

with open("notes.txt", "w") as file:
    file.write("Python Week 6 Notes\n")
    file.write("Topic: File Handling\n")
    file.write("Status: Mind blown\n")

print("File written!")
Enter fullscreen mode Exit fullscreen mode
File written!
Enter fullscreen mode Exit fullscreen mode

Reading it back:

with open("notes.txt", "r") as file:
    for line in file:
        print(line.strip())    # .strip() removes the \n at the end of each line
Enter fullscreen mode Exit fullscreen mode
Python Week 6 Notes
Topic: File Handling
Status: Mind blown
Enter fullscreen mode Exit fullscreen mode

Simple. But the moment students saw their own data surviving after the program closed - there was a visible shift in the room.


Reading a CSV File Manually

This is the moment the session had been building toward.

A CSV (Comma-Separated Values) file is the most common format for tabular data. Every spreadsheet, every database export, every dataset you'll ever work with -almost certainly starts as a CSV at some point.

Here's what our students.csv looked like:

name,course,score
amina waweru,data engineering,88
BRIAN OTIENO,Data Science,74
njeri kamau ,DATA ENGINEERING,91
kamau mwangi,data science,
wanjiku achieng,Data Engineering,79
aisha baraka,DATA SCIENCE,85
Enter fullscreen mode Exit fullscreen mode

Messy. Inconsistent capitalisation. One missing score. Trailing spaces. Real.

Reading it line by line:

with open("students.csv", "r") as file:
    header = file.readline()    # skip the header row
    print(f"Columns: {header.strip()}")

    for line in file:
        row = line.strip().split(",")
        print(row)
Enter fullscreen mode Exit fullscreen mode
Columns: name,course,score
['amina waweru', 'data engineering', '88']
['BRIAN OTIENO', 'Data Science', '74']
['njeri kamau ', 'DATA ENGINEERING', '91']
['kamau mwangi', 'data science', '']
['wanjiku achieng', 'Data Engineering', '79']
['aisha baraka', 'DATA SCIENCE', '85']
Enter fullscreen mode Exit fullscreen mode

Now we could see exactly what we were dealing with. Messy input, structured as lists. Time to clean it.


The Moment That Got Everyone: The Full Pipeline

We combined everything- file reading, string methods, validation, data structures - into one script. I walked through it step by step, building it live:

def clean_name(name):
    return name.strip().title()

def clean_course(course):
    return course.strip().title()

def parse_score(score_str):
    score_str = score_str.strip()
    if score_str.isdigit():
        return int(score_str)
    return None   # missing or invalid score

def calculate_grade(score):
    if score is None: return "N/A"
    if score >= 80: return "A"
    elif score >= 70: return "B"
    elif score >= 60: return "C"
    elif score >= 50: return "D"
    else: return "F"

# Read and process the file
students = []

with open("students.csv", "r") as file:
    file.readline()   # skip header

    for line in file:
        parts = line.strip().split(",")
        if len(parts) != 3:
            continue  # skip malformed rows

        name   = clean_name(parts[0])
        course = clean_course(parts[1])
        score  = parse_score(parts[2])
        grade  = calculate_grade(score)

        students.append({
            "name": name,
            "course": course,
            "score": score,
            "grade": grade
        })

# Print the cleaned report
print(f"\n{'='*55}")
print(f"  LUX ACADEMY - CLEANED STUDENT REPORT")
print(f"{'='*55}")
print(f"  {'NAME':<20} {'COURSE':<20} {'SCORE':<7} GRADE")
print(f"  {'-'*50}")

for s in students:
    score_display = str(s['score']) if s['score'] is not None else "MISSING"
    print(f"  {s['name']:<20} {s['course']:<20} {score_display:<7} {s['grade']}")

print(f"{'='*55}")

# Summary
valid_scores = [s['score'] for s in students if s['score'] is not None]
print(f"\n  Total students : {len(students)}")
print(f"  Missing scores : {len(students) - len(valid_scores)}")
print(f"  Class average  : {sum(valid_scores)/len(valid_scores):.1f}")
print(f"  Highest score  : {max(valid_scores)}")
print(f"  Lowest score   : {min(valid_scores)}")
Enter fullscreen mode Exit fullscreen mode
=======================================================
  LUX ACADEMY - CLEANED STUDENT REPORT
=======================================================
  NAME                 COURSE               SCORE   GRADE
  --------------------------------------------------
  Amina Waweru         Data Engineering     88      A
  Brian Otieno         Data Science         74      B
  Njeri Kamau          Data Engineering     91      A
  Kamau Mwangi         Data Science         MISSING N/A
  Wanjiku Achieng      Data Engineering     79      B
  Aisha Baraka         Data Science         85      A
=======================================================

  Total students : 6
  Missing scores : 1
  Class average  : 83.4
  Highest score  : 91
  Lowest score   : 74
Enter fullscreen mode Exit fullscreen mode

The room went silent when that output appeared.

Then Brian said: "We just built a data pipeline."

He wasn't wrong. Read raw data from a file. Clean it. Validate it. Structure it. Report on it. That's a pipeline - the same pattern that powers every data engineering workflow, just without the framework around it yet.

I told them: "When you get to Airflow, you'll write DAGs that do exactly this. The logic is identical - the scaffolding just gets more powerful."


Writing Results to a File

The last piece - saving the cleaned output so it persists:

with open("cleaned_students.csv", "w") as output:
    output.write("name,course,score,grade\n")

    for s in students:
        score_str = str(s['score']) if s['score'] is not None else ""
        output.write(f"{s['name']},{s['course']},{score_str},{s['grade']}\n")

print("Cleaned data saved to cleaned_students.csv ✅")
Enter fullscreen mode Exit fullscreen mode
Cleaned data saved to cleaned_students.csv ✅
Enter fullscreen mode Exit fullscreen mode

Input file in. Cleaned file out. The program did in seconds what would take a human twenty minutes of careful spreadsheet work — and it never makes a typo.


Practice Problems

Easy:

# 1. Write a program that asks for 3 lines of text and saves them to a file called "notes.txt"
# 2. Read "notes.txt" back and print each line numbered (1. line one, 2. line two...)
# 3. Clean this list of messy names using string methods:
#    names = ["  AMINA waweru", "brian OTIENO  ", "NJERI kamau  "]
Enter fullscreen mode Exit fullscreen mode

Medium:

# Write a function that reads a text file and returns:
# - Total number of lines
# - Total number of words
# - The longest line

def analyse_file(filename):
    pass  # your code here

# Test with any .txt file you create
Enter fullscreen mode Exit fullscreen mode

Challenge:

# Build a contact book that saves to and loads from a CSV file
# contacts.csv format: name,phone,email
#
# Your program should:
# 1. Load existing contacts from file on startup
# 2. Allow adding new contacts
# 3. Allow searching by name
# 4. Save all contacts back to the file on exit
#
# Bonus: validate that the email contains "@" and the phone is digits only
Enter fullscreen mode Exit fullscreen mode

What I Noticed Teaching This Session

1. "We just built a data pipeline" is the sentence I wait for every cohort. When a student names what they've built - without being told - it means they understood not just the code but the concept. Brian earned that moment.

2. The SQL comparison came up again unprompted. At this point, students with the SQL background are making connections constantly - strip() is TRIM(), split() is like parsing, filtering a list is a WHERE clause. This is the compounding return on teaching SQL first.

3. Messy data was a better teacher than clean data. I could have given them a perfectly formatted CSV. Instead I gave them one with caps inconsistency, a missing score, and trailing spaces. Every problem they hit was a real problem real data has. Fixing it felt like real work.

4. The with statement is a habit worth building early. Some students tried open() without with first. When I showed what happens if the program crashes mid-write without proper closure - they switched immediately and never looked back.


What's Coming in Week 7: Error Handling & Practical Modules

So far our programs assume everything goes right. The file exists. The score is a number. The user types what we expect.

Real programs don't get that luxury:

try:
    score = int(input("Enter score: "))
    print(f"Score accepted: {score}")
except ValueError:
    print("That's not a number. Please enter a valid score.")
except FileNotFoundError:
    print("File not found. Check the filename and try again.")
finally:
    print("Validation complete.")
Enter fullscreen mode Exit fullscreen mode

We'll also cover the csv module (which handles CSV files properly - quoted fields, commas in values, headers), json for API data, os for working with folders and paths, and datetime for timestamps.

Week 7 is where Python stops being fragile and starts being robust. See you then.


Try It Yourself

Create your own messy CSV - names in wrong cases, a missing value or two - and run the full pipeline on it. The messier you make it, the more satisfying the clean output.


I'm a data trainer in Nairobi running a full data programme -
Python foundations → Data Science or Data Engineering specialisations.
I write weekly about what we covered, what worked, and what surprised me.
Follow along or drop your questions in the comments.

Top comments (0)