Skip to content
Educora
Advanced20 min14 / 42

Files and a mini project: grade calculator

Learn to write to and read from files, then combine everything from the course in a grade calculator project.

Check yourself
In this lesson you will learn
  • Write to and read from a file with with open(...)
  • Tell the 'r', 'w' and 'a' modes apart
  • Combine variables, loops, functions, dictionaries and error handling in one program

As soon as a program ends, all its variables are wiped from memory: the game's high score, the grades in a register, the shopping list — all gone. To keep data, you need to write it to a file. In this lesson you will learn to work with files and then combine everything you have learned in this course in one real project — a grade calculator.

Writing and reading files

The open() function opens a file: the first argument is the file name and the second is the mode. The with statement closes the file automatically when the block ends — even if an error happens. encoding='utf-8' makes sure letters such as ö, ş and ç are stored correctly.

ModeMeaningIf the file already exists
'r'read (the default)its content is read; if there is no file — FileNotFoundError
'w'writethe old content is erased
'a'appendnew text is added at the end
Python
with open('notes.txt', 'w', encoding='utf-8') as f:
    f.write('Python is fun\n')
    f.write('Files keep data\n')

with open('notes.txt', encoding='utf-8') as f:
    for line in f:
        print(line.strip())
▸ Expected output
Python is fun
Files keep data

write() does not add a newline at the end, so we write the \n ourselves. When you read a file line by line with a for loop, that \n is still at the end of each line — strip() removes it. To get all the lines at once as a list, use readlines():

Python
with open('log.txt', 'w', encoding='utf-8') as f:
    f.write('Day 1: started Python\n')

with open('log.txt', 'a', encoding='utf-8') as f:
    f.write('Day 2: learned loops\n')

with open('log.txt', encoding='utf-8') as f:
    lines = f.readlines()
print(len(lines), 'lines')
print(lines[-1].strip())
▸ Expected output
2 lines
Day 2: learned loops

If you try to read a file that does not exist, you get a FileNotFoundError. As in the lesson on error handling, you can catch it with try / except:

Python
try:
    with open('missing.txt', encoding='utf-8') as f:
        print(f.read())
except FileNotFoundError:
    print('File not found, starting with an empty list.')
▸ Expected output
File not found, starting with an empty list.

Mini project: grade calculator

A teacher keeps students' grades in a simple text file: each line holds a name and grades separated by commas. This format is called CSV (comma-separated values). Our program will read the file, skip broken lines, calculate each student's average and write a report to a new file.

  1. 1
    Prepare the data

    Write the grades to grades.csv. We put a deliberate mistake (x) in one line to see how the program reacts.

  2. 2
    Read and parse the file

    Split each line with split(','): the first part is the name, the rest are grades. Convert them with int() and store them in a dictionary.

  3. 3
    Catch the errors

    int('x') raises a ValueError — catch it with try / except, print a warning and skip that line.

  4. 4
    Calculate and write the report

    Use functions to find the average and the level, write the results to report.txt and read it back to check.

Python
lines = ['Aysel,5,4,5,5', 'Murad,4,3,4', 'Leyla,5,5,4,5', 'Elvin,3,x,4', 'Nigar,2,3,3']
with open('grades.csv', 'w', encoding='utf-8') as f:
    f.write('\n'.join(lines))

journal = {}
with open('grades.csv', encoding='utf-8') as f:
    for line in f:
        parts = line.strip().split(',')
        name = parts[0]
        try:
            journal[name] = [int(m) for m in parts[1:]]
        except ValueError:
            print(f'Skipped {name}: bad data')
print(journal)
▸ Expected output
Skipped Elvin: bad data
{'Aysel': [5, 4, 5, 5], 'Murad': [4, 3, 4], 'Leyla': [5, 5, 4, 5], 'Nigar': [2, 3, 3]}
Steps 1–3: the file is created and read, and the broken line is skipped. The slice parts[1:] takes every part after the name.

Now let's split the calculation into two functions: average returns the mean, and level returns the level as a word (we chose the thresholds ourselves). A dictionary comprehension calculates all the averages in one line, and the result is written to report.txt:

Python
journal = {'Aysel': [5, 4, 5, 5], 'Murad': [4, 3, 4], 'Leyla': [5, 5, 4, 5], 'Nigar': [2, 3, 3]}

def average(scores):
    return sum(scores) / len(scores)

def level(avg):
    if avg >= 4.5:
        return 'excellent'
    elif avg >= 3.5:
        return 'good'
    elif avg >= 2.5:
        return 'satisfactory'
    return 'needs help'

averages = {name: average(s) for name, s in journal.items()}
with open('report.txt', 'w', encoding='utf-8') as f:
    for name, avg in averages.items():
        f.write(f'{name}: {avg:.2f} ({level(avg)})\n')

with open('report.txt', encoding='utf-8') as f:
    print(f.read().strip())
print(f'Best average: {max(averages.values()):.2f}')
▸ Expected output
Aysel: 4.75 (excellent)
Murad: 3.67 (good)
Leyla: 4.75 (excellent)
Nigar: 2.67 (satisfactory)
Best average: 4.75
Exercise

Write every fruit from fruits to the file fruits.txt, one per line (mode 'w'). Then read the file back and print its lines numbered from 1, in the form 1. apple.

Exercise · Python
fruits = ['apple', 'pomegranate', 'fig']
# 1) write each fruit on its own line to fruits.txt
# 2) read fruits.txt and print: 1. apple, 2. pomegranate, ...
▸ Expected output
1. apple
2. pomegranate
3. fig
Exercise

Mini project: every line of sales.csv has the form product,quantity,price. Read the file and add up the money earned for each product (quantity × price) in a dictionary. Skip a line with bad data using try/except and print Skipped: followed by that line. Finally print the products in alphabetical order in the form cup: 2.00 AZN, and at the very end a Total: line in the same format.

Exercise · Python
lines = ['pen,3,0.5', 'notebook,2,1.25', 'bag,1,x', 'pen,4,0.5']
with open('sales.csv', 'w', encoding='utf-8') as f:
    f.write('\n'.join(lines))

totals = {}
# 1) read sales.csv line by line: product,quantity,price
# 2) skip bad lines (print Skipped: and the line)
# 3) add quantity * price to totals[product]
# 4) print the products in alphabetical order, then the Total
▸ Expected output
Skipped: bag,1,x
notebook: 2.50 AZN
pen: 3.50 AZN
Total: 6.00 AZN

Key points

  • with open(name, mode, encoding='utf-8') as f: opens a file and closes it automatically when the block ends.
  • 'r' reads, 'w' erases and writes, and 'a' appends to the end.
  • write() does not add \n; strip() removes the \n from lines you read.
  • Reading a missing file raises FileNotFoundError — catch it with try / except.
  • CSV lines can be split into parts with split(',').

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
Which mode adds text to a file without erasing its old content?