From Python basics to a working project.
Over the past weeks, we have worked through an eight-part Python learning series, building the knowledge and skills needed to write clear, structured, and reusable Python programs.
In the series, we explored conditional statements, loops, functions, and other essential programming concepts, gradually learning how each one helps us solve a different kind of problem.
If you missed any of the articles in the series or would like a refresher before continuing, take a moment to explore them here.
Students Result Management System
In this article, we will build a Student Results Management System from scratch. In the process, we will revisit many of the concepts we've covered throughout the series and see how they work together to build a complete program.
Project Scenario
A local High School has hired you to build a system for managing student examination results. The school requires a program that can:
- Add a new student and their marks
- Read and display all students already saved
- Calculate each student's average mark and grade
- Find the top student and class average
- Save all data to a file (so it persists between runs)
- Print a formatted report for the whole class
We'll build the application step by step, and test each component before moving on to the next.
Step 1: Setting Up the Project
For this project, I used Visual Studio Code with the Jupyter Notebook and Python extensions. The main program was developed in a Jupyter Notebook, while the supporting modules were created as Python files. You can use another Python environment if you prefer; the concepts and syntax remain the same.
Begin by creating a folder named Student_results_system on your computer. Inside the project folder, create the following Python files:
Student_results_system/
│
├── main.py
├── logic.py
├── file_handler.py
└── report.py
Each file will have a specific responsibility throughout the project:
- main.py : Controls the overall program flow and displays the menu.
- logic.py : Contains functions for calculating averages, and assigning grades.
- file_handler.py : Saves and loads student records to and from a CSV file.
- report.py : Generates and displays the final student report.
With our project structure in place, we're ready to start building.
Step 2: Building the Interactive Menu
In our Students Results Management System, the starting point is the main menu.
We will build the basic menu structure that allows users to select an option. We want the program to keep running so that the user can choose different options until they decide to exit. For this, we will use a while loop.
So in the main.ipynb script, let us create the following menu
print("\n====STUDENT RESULTS MANAGEMENT SYSTEM ====")
print("1. Add Student")
print("2. View Students")
print("3. Generate Report")
print("4. Exit")
while True:
choice = input("Select an option: ")
if choice == "1":
print("Add Student selected.")
elif choice == "2":
print("View Students selected.")
elif choice == "3":
print("Generate Report selected.")
elif choice == "4":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
At this stage, the options will not perform their intended tasks yet. However, we need to test the menu before adding the rest of the code.
Test it: Run the program and test each menu option. Selecting options 1, 2, and 3 should display a confirmation message, while selecting 4 should terminate the program. If any other value is entered, an 'Invalid choice' message is displayed, and you're prompted again.
Step 3: Adding Student Records
We will now begin by asking the user to enter a student's name and marks. Since the system will eventually store multiple students, we will create an empty list named students. Every time a new student is added, their details will be stored in this list as a dictionary.
Let's begin by creating an empty list at the very beginning of the code:
students = []
We'll then modify the Add Student option to collect the student's details.
In the main.ipynb notebook, replace
print("Add Student selected.")
The code then becomes:
students = []
subjects = ["Mathematics", "English", "Science", "History", "Kiswahili", "Physics"]
while True:
print("\n===== STUDENT RESULTS MANAGEMENT SYSTEM =====")
print("1. Add Student")
print("2. View Students")
print("3. Generate Report")
print("4. Exit")
choice = input("Select an option: ")
if choice == "1":
name = input("Enter student name: ")
student = {"name": name}
for subject in subjects:
mark = float(input(f"Enter {subject} marks: "))
student[subject] = mark
students.append(student)
print(f"\n{name} has been added successfully!")
elif choice == "2":
print("View Students selected.")
elif choice == "3":
print("Generate Report selected.")
elif choice == "4":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
You'll notice we have introduced a list called subjects, which allows us to use a loop to collect marks for each subject, rather than having multiple separate input statements for each subject.
At this stage, the program can accept multiple student records.
Test it: Add a student and confirm that their name and marks for all six subjects are accepted successfully. Check that the
[name] has been added successfully!confirmation appears.
Step 4: Viewing Student Records
When the user selects Option 2, the program should display all the students entered so far, together with their marks in each subject. If no students have been added yet, the program should inform the user instead of displaying an empty report.
So our View Students section is updated as follows;
students = []
subjects = ["Mathematics", "English", "Science", "History", "Kiswahili", "Physics"]
while True:
print("\n===== STUDENT RESULTS MANAGEMENT SYSTEM =====")
print("1. Add Student")
print("2. View Students")
print("3. Generate Report")
print("4. Exit")
choice = input("Select an option: ")
choice = input("Select an option: ")
if choice == "1":
name = input("Enter student name: ")
student = {"name": name}
while mark < 0 or mark > 100:
print("Mark must be between 0 and 100.")
mark = float(input(f"Enter {subject} marks: "))
student[subject] = mark
students.append(student)
print(f"\n{name} has been added successfully!"
elif choice == "2":
if not students:
print("\nNo student records found.")
else:
print("\n===== STUDENT RECORDS =====")
for student in students:
print(f"\nStudent: {student['name']}")
for subject in subjects:
print(f"{subject}: {student[subject]}")
elif choice == "3":
print("Generate Report selected.")
elif choice == "4":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
Test it: Add a few students then select
View Studentsoption. The program should display every student and their marks.
Step 5: Calculating Student Averages and Grades
We can now record and retrieve student details and exam results from our Student Records Management System. We would now like to calculate each student's average mark and assign a grade based on that average.
As programs grow, separating different responsibilities into modules makes the code more efficient, easier to read, test and maintain. This next step will be placed in the logic.py file we created in Step 1 above.
In logic.py, create the following function:
def calculate_results(student):
marks = [
student["Mathematics"],
student["English"],
student["Science"],
student["History"],
student["Kiswahili"],
student["Physics"]]
average = sum(marks) / len(marks)
if average >= 80:
grade = "A"
elif average >= 70:
grade = "B"
elif average >= 60:
grade = "C"
elif average >= 50:
grade = "D"
else:
grade = "E"
return average, grade
Next, import the function into main.py
from logic import calculate_results
This allows main.py to access the grading logic without rewriting it, keeping the code organized, and reusable. If the grading criteria changes in the future, we only need to update the function.
Finally, update the View Students option to calculate and display each student's average and grade:
elif choice == "2":
if not students:
print("\nNo student records found.")
else:
print("\n===== STUDENT RECORDS =====")
for student in students:
average, grade = calculate_results(student)
print(f"\nStudent: {student['name']}")
for subject in subjects:
print(f"{subject}: {student[subject]}")
print(f"Average: {average:.2f}")
print(f"Grade: {grade}")
Test it: Run the program again and add a few students with different marks. When you select
View Students, each student's marks should now be accompanied by their calculatedaverageandfinal grade.
Step 6: Saving Student Records to a CSV File
Our Student Results Management System can add students, display their records, and calculate averages and grades. However, once the program closes, all the student records are lost.
To prevent this, we will save each student record to a CSV file. Remember the file_handler.py file we created in step 1? That is where we will add the function responsible for saving student records.
Open file_handler.py and add the following code:
import csv
import os
def save_student(student):
file_exists = os.path.isfile("students.csv")
with open("students.csv", "a", newline="") as file:
writer = csv.DictWriter(
file,
fieldnames=["name", "Mathematics","English","Science","History","Kiswahili","Physics"])
if not file_exists:
writer.writeheader()
writer.writerow(student)
The save_student() function saves a student record to students.csv. It first checks whether the file already exists, then opens it in append mode so existing records aren't overwritten. If the file is new, it adds the column headers before writing the student's record as a new row.
We will then import the function from file_handler.py into main.ipynb:
from file_handler import save_student
Finally, update the Add Student option so that each new record is saved immediately after being added to the list:
students.append(student)
save_student(student)
print(f"\n{name} has been added successfully!")
Test it: Run the program and add a few students. A new file named students.csv should automatically be created in your project folder. Opening the file should display all the student records entered into the system.
Step 7: Loading Student Records
Our application now saves student records to a CSV file, ensuring they aren't lost when the program closes. However, each time the application starts, the students list is empty.
We'll create a function that reads the CSV file and loads all existing records into the students list when the program starts.
In the file_handler.py file, we will add the following function:
def load_students():
students = []
if not os.path.isfile("students.csv"):
return students
with open("students.csv", "r") as file:
reader = csv.DictReader(file)
for row in reader:
student = {"name": row["name"]}
for subject in row:
if subject != "name":
student[subject] = float(row[subject])
students.append(student)
return students
The load_students() function reads the saved records from students.csv and converts them back into a list of student dictionaries that the program can work with. It checks that the file exists, reads each student record, converts the marks back to numbers, and returns the complete list.
Next we import the function into main.ipynb:
from file_handler import load_students
Finally, at the very start of the code replace:
students = []
with:
students = load_students()
Now, whenever the program starts, it will automatically load all previously saved student records from the CSV file.
Test it: Run the program, adding a couple of student records. Close and reopen the program, then select
View Studentswithout adding any new records. You should be able to see the previously recorded details.
Step 8: Generating a Student Performance Report
The final feature is to generate a summary report that provides an overview of the class performance.
The report will answer:
- How many students are in the system?
- What is the class average?
- Who is the top-performing student?
- Who has the lowest average?
To keep our project organized, we'll create the function in the report.py file.
from logic import calculate_results
def generate_report(students):
if not students:
print("\nNo student records found.")
return
print("\n="*30)
print(" EASTSIDE HIGH SCHOOL - REPORT")
print("="*30)
print(f"{'Name':<20} {'Average':<10} {'Grade':<5}")
print("-"*30)
class_total = 0
highest_average = -1
highest_student = ""
for student in students:
average, grade = calculate_results(student)
print(f"{student['name']:<20} {average:<10.1f} {grade:<5}")
class_total += average
if average > highest_average:
highest_average = average
highest_student = student["name"]
class_average = class_total / len(students)
print("-"*30)
print(f"Class Average: {class_average:.1f}")
print(f"Top Student: {highest_student} ({highest_average:.1f})")
print("="*30)
Next, import the generate_report function to the main.ipynb as follows;
from report import generate_report
In the choice == 3 section (Generate Report) in the main.ipynb file, replace
print("Generate Report selected.")
With:
generate_report(students)
Conclusion
And that's a wrap on the Student Results Management System!
In this project, we brought together many of the concepts from the Python Fundamentals series, including loops, functions, dictionaries, file handling, and modules, and saw how these individual concepts can work together to create a functional Python application.
You can find the folder structure and all the code we have written here: Student Result Management System
The system is simple, but there is plenty of room to experiment and improve it. Keep practicing, keep building, and don't stop learning.
If you build your own version, put your own spin on it, or find a better way of doing something, feel free to share it. I'd love to see what you come up with and hear your ideas for improving the system.
Top comments (0)