Loading

1. Why Programs Need to Remember Things

Think of a notebook. While you're writing in it, all your notes exist. When you close it and put it down, those notes are still there — because they're on paper, not just in your head. Now imagine if every time you closed your notebook, every page went blank. That would be useless.

That's exactly how a Python program works with its variables. Every number, name, and list you store in a variable lives in RAM — temporary memory. The moment the program stops running, all of it is gone. Files are your program's notebook: they let data survive after the program closes.

Three File Formats You'll Use Most

  • .txt files — plain text, one line after another. Simple and universal. Good for logs, notes, and raw data.
  • .csv files — "Comma Separated Values." A table in text form — each row is a line, each column is separated by a comma. This is how spreadsheets export data, and how Python reads it.
  • .json files — structured data in key-value pairs, like a Python dictionary. Used heavily in APIs, web apps, and config files. Easy for both humans and machines to read.
Key Idea

Variables store data temporarily in RAM. Files store data permanently on disk. Any time your program needs to remember something after it closes — use a file (or a database).

2. Reading Files

Python makes reading files remarkably straightforward. The main function you'll use is open() — it opens a file and gives you a file object you can read from.

The open() Function and Modes

The second argument to open() is the mode — a short string telling Python what you want to do with the file:

  • 'r' — Read (default). Open for reading. Fails if the file doesn't exist.
  • 'w' — Write. Creates the file if it doesn't exist. Wipes it clean if it does.
  • 'a' — Append. Adds to the end of the file without deleting what's there.

Three Ways to Read

  • read() — reads the entire file as one big string
  • readline() — reads one line at a time (useful for very large files)
  • readlines() — reads all lines and returns them as a list

Always Use the with Statement

When you open a file, your program holds on to it (like holding a lunch box open). If your program crashes before you close it, the file can get corrupted or stay locked. The with statement puts a lid on the lunch box for you — automatically closing the file when the block ends, even if something goes wrong.

Python — reading a file line by line
# Suppose marks.txt contains:
# Arjun,85
# Priya,92
# Rahul,78

with open('marks.txt', 'r') as file:
    for line in file:
        line = line.strip()      # remove the newline at the end
        print(line)

# Output:
# Arjun,85
# Priya,92
# Rahul,78
Python — reading all lines into a list
with open('marks.txt', 'r') as file:
    lines = file.readlines()

# lines is now: ['Arjun,85\n', 'Priya,92\n', 'Rahul,78\n']
# Process each student:
for entry in lines:
    name, mark = entry.strip().split(',')
    print(f"{name} scored {mark}")
Try It

Create a text file called subjects.txt with five subject names, one per line. Write Python code to read it and print each subject with a number in front — like a numbered list.

3. Writing and Appending Files

Reading is great for getting data in. Writing lets your program save results, logs, and reports that other people (or programs) can use later.

Writing with 'w' Mode

Mode 'w' creates a new file if it doesn't exist, or overwrites the existing one completely if it does. Think of it as tearing out all the old pages and starting fresh.

Python — writing student marks to a file
students = [
    ('Aisha', 88),
    ('Dev', 74),
    ('Meera', 95),
]

with open('results.txt', 'w') as file:
    file.write("Student Results\n")
    file.write("=" * 30 + "\n")
    for name, mark in students:
        file.write(f"{name}: {mark}\n")

print("File written successfully.")
Important Warning

Opening a file with 'w' mode deletes everything that was in it before — instantly and silently. Always double-check your mode before writing to an existing file with important data.

Appending with 'a' Mode

Mode 'a' is safer when you want to add new data to an existing file without destroying the old data. It's like writing on the next blank page of a notebook instead of tearing out the existing ones.

Python — appending a new student to the results file
# This runs later — adds one more student without wiping the file
with open('results.txt', 'a') as file:
    file.write("Kiran: 91\n")

print("New student added.")

4. Error Handling — Building Crash-Proof Programs

A seatbelt doesn't mean you're a bad driver. It means you're a smart one. You wear it not because you expect to crash, but because if something unexpected happens, you want to walk away. Error handling in Python is exactly that seatbelt.

Without error handling, a single unexpected situation — a file that doesn't exist, a user typing letters where a number was expected, a division by zero — will bring your entire program crashing down with a red error message. With error handling, your program can catch the problem, tell the user something helpful, and keep running.

The try / except Block

You put the code that might fail inside the try block. If it fails, Python jumps to the except block instead of crashing.

Python — basic try/except
try:
    result = 10 / 0        # This will cause a ZeroDivisionError
    print(result)
except ZeroDivisionError:
    print("You can't divide by zero!")

Catching Specific Exceptions

Python has many built-in exception types. Being specific about which exception you're catching makes your code clearer and prevents accidentally hiding real bugs:

  • FileNotFoundError — the file you tried to open doesn't exist
  • ValueError — the value is the wrong type (e.g., trying to convert "hello" to an int)
  • ZeroDivisionError — dividing by zero
  • IndexError — accessing a list index that doesn't exist
  • KeyError — accessing a dictionary key that doesn't exist

else and finally

The else block runs only if no exception occurred — your "success" path. The finally block runs no matter what — useful for cleanup code like closing a connection.

Python — safe file reader with full error handling
def read_marks_file(filename):
    try:
        with open(filename, 'r') as file:
            content = file.read()
    except FileNotFoundError:
        print(f"Sorry, '{filename}' was not found.")
        print("Please check the file name and try again.")
        return None
    except PermissionError:
        print(f"No permission to read '{filename}'.")
        return None
    else:
        print("File read successfully!")
        return content
    finally:
        print("Attempted to read file.")   # Always runs

data = read_marks_file('marks.txt')
if data:
    print(data)

Raising Your Own Exceptions

Sometimes you want to deliberately trigger an error when something is wrong with the data your program receives. You can raise exceptions yourself using raise:

Python — raising custom exceptions
def set_marks(mark):
    if not isinstance(mark, (int, float)):
        raise TypeError("Marks must be a number.")
    if mark < 0 or mark > 100:
        raise ValueError(f"Marks must be between 0 and 100, got {mark}.")
    return mark

try:
    m = set_marks(110)
except ValueError as e:
    print(f"Invalid input: {e}")

5. Practical Project: Student Results Manager

Let's put it all together. This program reads student names and marks from a CSV file, calculates their grade, and writes a formatted results file. This is a real pattern — it's how data processing scripts are written in the industry.

First, create a file called students.csv with this content:

students.csv
name,marks
Aisha,88
Dev,74
Meera,95
Kiran,62
Arjun,45
Python — student results manager (complete program)
def get_grade(mark):
    """Convert a numeric mark to a letter grade."""
    if mark >= 90:
        return 'A+'
    elif mark >= 80:
        return 'A'
    elif mark >= 70:
        return 'B'
    elif mark >= 60:
        return 'C'
    elif mark >= 50:
        return 'D'
    else:
        return 'F'

def process_results(input_file, output_file):
    """Read students.csv, calculate grades, write results.txt."""
    students = []

    # Read the CSV
    try:
        with open(input_file, 'r') as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"Error: '{input_file}' not found.")
        return

    # Skip the header row, process the rest
    for line in lines[1:]:
        line = line.strip()
        if not line:          # skip empty lines
            continue
        try:
            name, mark_str = line.split(',')
            mark = int(mark_str)
            grade = get_grade(mark)
            students.append((name.strip(), mark, grade))
        except ValueError:
            print(f"Skipping bad line: '{line}'")

    if not students:
        print("No valid student data found.")
        return

    # Write the results file
    with open(output_file, 'w') as f:
        f.write("STUDENT RESULTS REPORT\n")
        f.write("=" * 35 + "\n\n")
        for name, mark, grade in students:
            f.write(f"{name:<15} {mark:>3}/100   Grade: {grade}\n")
        f.write("\n" + "=" * 35 + "\n")
        avg = sum(m for _, m, _ in students) / len(students)
        f.write(f"Class Average: {avg:.1f}\n")

    print(f"Results written to '{output_file}'.")

# Run the program
process_results('students.csv', 'results.txt')
Try It Yourself

Add a function called search_student(name, filename) that reads the CSV and prints the marks and grade for that specific student. If the student isn't found, print a helpful message instead of crashing.