Build a Student Record Manager
Build a Python program covering every core concept on your exam syllabus.
Introduction
30 Second Summary
Every university tracks student names, scores, and grades. Behind that process is code that stores data, applies rules, and produces results. Understanding how that code works line by line is exactly what your written exam will test.
In this project, you will build a Student Record Manager in Python that stores student data, calculates grades, and organizes records using every core Python concept on your exam syllabus.
What You'll Build
A single Python file that grows step by step, covering variables, conditionals, loops, data structures, list comprehensions, and functions.
By the end of this project, you'll have:
- A working Student Record Manager that stores, grades, and displays student data from a single Python file.
- Hands-on practice with every Python concept on your exam syllabus, including variables, casting, operators, conditionals, loops, iterables, data structures, and functions.
- Logic-tracing skills for predicting what code outputs at each step. This is the exact skill your written exam tests.
- Secret Mission: Refactor the entire program into an OOP design using classes, inheritance, and methods.
Are there any prerequisites?
You need Python 3 and VS Code installed on your machine. No external packages or accounts are required. If you already have both installed, you are ready to start.
Set Up Your Project File
Before you start building the Student Record Manager, you need a workspace. This means a dedicated folder to hold your code and a Python file to write it in.
In this step, you will confirm Python is ready on your machine, create your project folder, and write your very first line of code.
In this step, get ready to:
- Confirm Python is ready to use.
- Create a project folder and open it in VS Code.
- Write and run your first line of Python code.
Confirm Python is installed
Your machine already has Python installed. A quick version check confirms everything is working before you write any code.
- Press Ctrl+Alt+T to open your terminal.
- Check your Python version by running this command:
python3 --version
You should see a version number printed, like Python 3.12.0 or similar. The exact number does not matter as long as it starts with Python 3.
Don't see a version number?
If you see command not found, try running python --version instead (without the 3). Some Linux installations use python instead of python3 as the command name.
help me figure out why python3 --version isn't working on my Linux machine
Create your project folder
Every project needs its own folder to keep files organized. You will create a folder called student_records on your Desktop so it is easy to find.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir student_records
cd student_records
- Confirm the folder exists by running:
pwd
You should see a path ending in /Desktop/student_records.
- Open this folder in VS Code by running:
code .
VS Code opens with your student_records folder loaded in the sidebar.
VS Code didn't open?
If you see command not found, the code command is not in your PATH. Open VS Code manually, then click File > Open Folder and select student_records from your Desktop.
help me get the code command working in my Linux terminal so I can open VS Code from the command line
Write and run your first Python code
Now that VS Code is open in your project folder, you will create your first Python file and run it. This confirms your full workflow is ready: edit in VS Code, run in the terminal.
- In VS Code, hover over the STUDENT_RECORDS section in the left sidebar.
- Click the New File icon (a page with a plus sign).
- Type student_records.py as the file name and press Enter.
The file opens in the editor. Now add your first line of code.
- Type the following code into student_records.py:
print("Student Record Manager")
What does this code do?
print() is a built-in Python function that displays text in the terminal. The text inside the quotes is called a string. Python prints it exactly as written.
- Save the file by pressing Ctrl+S.
- Open the integrated terminal in VS Code by pressing Ctrl+` (the backtick key, above Tab).
- Run your code by entering this command:
python3 student_records.py
You should see Student Record Manager printed in the terminal.
Don't see the output?
Make sure you saved the file before running the command. Check the file tab in VS Code for a white dot, which means unsaved changes.
If you see No such file or directory, your terminal is not in the student_records folder. Run pwd to check your location, and use cd ~/Desktop/student_records to get back.
help me figure out why python3 student_records.py is not printing anything in my terminal
✔️ Awesome, I've got everything!
Great. Double check you have saved student_records.py and that your terminal shows Student Record Manager when you run it.
ⓧ I'd like to double check the full code
Here is the complete student_records.py file at this stage:
print("Student Record Manager")
Your environment is ready and your first Python file is running. Next up, you will add variables, data types, and operators to start building real student data.
Add Variables, Data Types, Casting, and Operators
Your environment is ready and Python is running. Now it's time to store real data in your program.
Every program needs data to work with. In this step, you'll create variables to hold a student's information and use Python's operators to calculate a percentage score from raw marks.
In this step, get ready to:
- Create variables for a student's name, ID, marks, and registration status.
- Use arithmetic operators to calculate a percentage and cast between types.
- Understand comparison and logical operators for evaluating conditions.
Create variables to store student data
A variable is a named container that holds a value. Python has several built-in data types to represent different kinds of information.
What are Python's basic data types?
Python has four basic types you'll use constantly.
- str (string) holds text like names and IDs.
- int (integer) holds whole numbers.
- float holds decimal numbers.
- bool (boolean) holds True or False.
- Replace everything in student_records.py with the following code:
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
What does this code do?
The top comments describe what this file will cover by the end of the project. The print() line displays a title banner when the program runs.
Each variable stores one piece of student data. student_name is a string, marks_obtained is an integer, and is_registered is a boolean. Python figures out the type automatically from the value you assign.
- Save student_records.py.
Seeing a red underline or syntax error?
- Make sure every string is enclosed in matching quotes. An opening " needs a closing ".
- Check that True has a capital T. Python booleans are case-sensitive.
Why is Python giving me a syntax error on my variables?
Use arithmetic operators and casting to compute a percentage
Variables on their own just sit there. Operators let you do calculations with them. Casting lets you convert a value from one type to another.
- Add the following code below is_registered = True in student_records.py:
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
What does this code do?
- The / operator divides marks_obtained by total_marks, and * multiplies the result by 100 to get a percentage.
- int(percentage) casts the float value to an integer, dropping the decimal part. This is called casting.
- type(percentage) returns the data type of the variable so you can inspect it at runtime.
- The f"..." syntax is an f-string. It lets you embed variables directly inside a string using curly braces.
- Save student_records.py.
- Run the file in your terminal by running this command:
python3 student_records.py
- You should see output showing the student name, percentage as a float, percentage as an integer, the registration status, and the type displayed as <class 'float'>.
Seeing a NameError?
- A NameError means Python cannot find a variable you referenced. Check that your variable names in the print statements match exactly what you defined above (including underscores and lowercase).
- Make sure the calculation code appears below the variable declarations, not above them. Python reads top to bottom.
Help me fix a NameError in my student records program.
What other arithmetic operators does Python have?
You used / (division) and * (multiplication) above. Python also supports these arithmetic operators:
- + addition, - subtraction.
- // floor division (rounds down to the nearest whole number).
- % modulo (gives the remainder after division).
- ** exponentiation (raises a number to a power).
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here is what your complete student_records.py should look like so far:
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
Understand comparison and logical operators
Arithmetic operators calculate values. Comparison operators ask questions about values and return True or False. You will use these in the next step to build grading logic.
What are comparison operators?
Comparison operators compare two values and return a boolean (True or False).
- == equal to, != not equal to.
- > greater than, < less than.
- >= greater than or equal to, <= less than or equal to.
For example, percentage >= 40 evaluates to True if the student passed (since your percentage is 78.0, this would be True).
What are logical operators?
Logical operators combine multiple conditions into one expression.
- and returns True only if both sides are true.
- or returns True if at least one side is true.
- not flips a boolean from True to False or vice versa.
For example, percentage >= 40 and is_registered is True only if the student both passed AND is registered. You will use these to build grading logic in the next step.
What are assignment operators?
Assignment operators update a variable's value in place. += adds to the current value (so count += 1 is the same as count = count + 1). -= subtracts from the current value. You will see these in loops later.
Practice tracing your code mentally
Tracing means reading code line by line and predicting what each variable holds at each point. This is exactly what your written exam tests. Before looking at the terminal output, try it now.
- Look at your code and answer these questions without running it:
Trace these values in your head
- What does marks_obtained / total_marks produce? (156 / 200 = 0.78)
- What does percentage hold after the multiplication? (0.78 * 100 = 78.0, a float)
- What does percentage_int hold after casting? (int(78.0) = 78, an integer with no decimal)
- What will type(percentage) print? (<class 'float'> because division always produces a float in Python)
Now run your file again to check your predictions.
- Confirm your predictions by running:
python3 student_records.py
- Your terminal should display the student name, percentage as 78.0, percentage as int 78, registered as True, and type as <class 'float'>.
Build this habit for your exam
On a written exam, you cannot run the code. You have to trace it mentally. Every time you write code in this project, pause and predict the output before running it. This is the single most valuable exam skill you can practice.
You now have a working program that stores student data in variables, calculates a percentage using arithmetic operators, and casts between types. Next up, you'll add conditional logic to assign letter grades based on the score.
Write Conditional Statements and Loops
Your Student Record Manager stores data, but it can't make any decisions yet. A grading system needs to look at a score and decide which grade to assign.
In this step, you'll write conditional logic that assigns letter grades and restructure your file into a clean layout with functions at the top. You'll also learn how loops work so you can trace their logic in exam questions.
In this step, get ready to:
- Write a grading function using if/elif/else conditional logic.
- Restructure your code with functions at the top and a main block.
- Trace loop patterns mentally to prepare for exam questions.
Write your grading function with if/elif/else
Python evaluates if/elif/else conditions from top to bottom and stops at the first one that is True. This is how your grading system decides which letter to assign.
- In student_records.py, select all existing code and delete it. You'll replace it with a restructured version.
- Paste this code, which starts with the file header comments and your new grading function:
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
# --- Functions ---
def calculate_grade(score):
"""Take a numeric score, return a letter grade."""
if score >= 70:
return "A"
elif score >= 60:
return "B"
elif score >= 50:
return "C"
elif score >= 40:
return "D"
else:
return "F"
What does this code do?
The calculate_grade function takes a numeric score and checks it against thresholds from highest to lowest.
- if score >= 70 is checked first. If it's True, Python returns "A" and skips everything else.
- elif means "else if". Python only checks it when all conditions above were False.
- else catches anything below 40 because no earlier condition matched.
Why does the order of conditions matter?
If you checked score >= 40 first, a score of 90 would get a "D" because 90 is also >= 40. Python stops at the first True condition. Always put the most restrictive condition at the top.
Restructure your code with a main block
Professional Python files separate function definitions (at the top) from the code that runs those functions (at the bottom). The if __name__ == "__main__": line tells Python to only run that block when you execute the file directly.
- Directly below the calculate_grade function, add the following main block. This contains your existing variables (now indented) plus a new conditionals section at the end:
if __name__ == "__main__":
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
# --- Conditionals ---
grade = calculate_grade(percentage)
passed = percentage >= 40
print(f"Grade: {grade}")
print(f"Passed: {passed}")
print()
What's happening here?
- if __name__ == "__main__": creates a "main block". Code inside it only runs when you execute the file directly with python3 student_records.py.
- All the existing variable code is now indented one level (4 spaces) under this block.
- grade = calculate_grade(percentage) calls your new function with the percentage value (78.0) and stores the returned letter grade.
- passed = percentage >= 40 uses a comparison operator that evaluates to True or False.
- Save student_records.py.
- Run your file by entering this command in the terminal:
python3 student_records.py
- You should see all the previous output, plus two new lines: Grade: A and Passed: True.
Seeing an IndentationError?
- Every line inside if __name__ == "__main__": must be indented by exactly 4 spaces. Check that none of your variable lines are still at the left margin.
- Make sure the def calculate_grade(score): line is NOT indented under the if __name__ block. Functions go at the top level.
Help me fix my IndentationError in student_records.py
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here is the complete student_records.py file at this point. Compare yours carefully.
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
# --- Functions ---
def calculate_grade(score):
"""Take a numeric score, return a letter grade."""
if score >= 70:
return "A"
elif score >= 60:
return "B"
elif score >= 50:
return "C"
elif score >= 40:
return "D"
else:
return "F"
if __name__ == "__main__":
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
# --- Conditionals ---
grade = calculate_grade(percentage)
passed = percentage >= 40
print(f"Grade: {grade}")
print(f"Passed: {passed}")
print()
Trace your conditional logic mentally
Your written exam will give you a block of code and ask "what does this output?" The skill being tested is your ability to step through code line by line, tracking what each variable holds.
Tracing exercise: what does calculate_grade(55) return?
Walk through it top to bottom:
- Is 55 >= 70? No. Skip to the next elif.
- Is 55 >= 60? No. Skip again.
- Is 55 >= 50? Yes. Return "C". Stop. Nothing below this runs.
This top-to-bottom, stop-at-first-True behaviour is what your exam tests. Practice this with different scores (35, 40, 69, 70) until the pattern is automatic.
Understand loops and iterables for your exam
Loops let Python repeat a block of code. You'll use loops extensively in the next step when you have multiple students to process. For now, learn the patterns so you can trace them on paper.
What is a for loop?
A for loop visits each item in a sequence one at a time. Combined with range(), it repeats a fixed number of times. For example, for i in range(5) runs the indented body 5 times, with i taking values 0, 1, 2, 3, 4.
You can also loop directly over lists, strings, and other iterables. Python handles the indexing for you.
What is a while loop?
A while loop keeps running as long as its condition is True. You must manually update the variable that controls the condition, otherwise the loop runs forever.
For example, if i = 0 and the loop says while i < 3 with i += 1 inside, it runs 3 times (i = 0, 1, 2) then stops when i reaches 3.
What are enumerate() and zip()?
- enumerate() gives you both the index and the value at each step. Instead of tracking a counter manually, Python hands you the position number alongside each item.
- zip() pairs up items from two sequences so you can loop over them together. If you have a list of names and a list of grades, zip(names, grades) gives you one name and one grade per iteration.
Tracing exercise: how many times does this loop run?
Imagine this code: count = 0, then i = 0, then while i < 5 with count += 1 and i += 1 inside. Trace it:
- Iteration 1: i=0, condition 0<5 is True, count becomes 1, i becomes 1.
- Iteration 2: i=1, condition 1<5 is True, count becomes 2, i becomes 2.
- Iteration 5: i=4, condition 4<5 is True, count becomes 5, i becomes 5.
- Check: i=5, condition 5<5 is False. Loop stops. Final count is 5.
On your exam, draw a small table with columns for each variable and one row per iteration. This makes loop tracing visual and prevents mistakes.
Key loop keywords to know
- break exits the loop immediately, skipping all remaining iterations.
- continue skips the rest of the current iteration and jumps to the next one.
- range(start, stop, step) generates numbers from start up to (but not including) stop. The stop value is never reached.
Your file now has clean structure with a reusable function at the top and a main block below. Next up, you'll build the data structures that store multiple students, and put your loops into action processing real records.
Build Data Structures
Your program can store one student's data and calculate their grade. A real record manager needs to handle multiple students at once.
Python gives you four built-in data structures for organizing collections of data: lists, tuples, sets, and dictionaries. Each one has different rules about what you can change, whether order matters, and whether duplicates are allowed.
In this step, get ready to:
- Store multiple student names in a list and sort them.
- Group fixed student data into a tuple.
- Track unique courses with a set and compare sets.
Store student names in a list
A list is a mutable, ordered collection. You can add items, remove items, and rearrange them after creation. This makes lists ideal for data that changes over time, like a growing class roster.
- In student_records.py, find the last print() at the bottom of your Conditionals section.
- Add the following code below it to create and sort a list of student names:
# --- Data Structures ---
# List - mutable, ordered
student_names = ["Jeffrey", "Ada", "Chidi", "Bola", "Emeka"]
student_names.append("Fatima")
student_names.sort()
print(f"Sorted students: {student_names}")
What does this code do?
- student_names = [...] creates a list with five names. Square brackets [] always mean "list" in Python.
- .append("Fatima") adds a sixth name to the end. The list grows because lists are mutable.
- .sort() rearranges the list alphabetically in place. It modifies the original list rather than creating a new one.
- Save student_records.py.
- Run the file in your terminal with python3 student_records.py. You should see Sorted students: ['Ada', 'Bola', 'Chidi', 'Emeka', 'Fatima', 'Jeffrey'] printed after your existing output.
Not seeing the sorted list?
- Make sure your new code is indented with 4 spaces, at the same level as the other code inside if __name__ == "__main__":. Python uses indentation to determine what belongs inside a block.
- Check that you added the code below the last print() line, not above it or outside the if block.
Help me fix my list code in student_records.py
What is a list?
A list is Python's most flexible data structure. It keeps items in order, allows duplicates, and lets you change its contents after creation. Think of it like a class register where students can be added, removed, or rearranged.
On your exam, you might be asked "what does .append() do?" The answer: it adds one item to the end of the list and modifies the list in place.
Group fixed data in a tuple
Some data should never change after it is created. A student's name and matric number are fixed facts. Tuples are immutable collections that protect this kind of data from accidental modification.
- Add the following code directly below your list print statement:
# Tuple - immutable, ordered
student_info = ("Jeffrey", "CSC/2025/001", "Computer Science")
name, matric, department = student_info # tuple unpacking
print(f"Unpacked: {name}, {matric}, {department}")
What does this code do?
- student_info = (...) creates a tuple with three items. Parentheses () signal a tuple.
- name, matric, department = student_info is tuple unpacking. Python assigns each tuple item to a separate variable in one line.
- If you tried student_info[0] = "New Name", Python would raise a TypeError: 'tuple' object does not support item assignment. That is immutability in action.
- Save student_records.py and run it again.
- You should see Unpacked: Jeffrey, CSC/2025/001, Computer Science printed after the sorted list.
Seeing a ValueError?
Tuple unpacking requires exactly as many variable names on the left as there are items in the tuple. If you have three items in the tuple, you need exactly three variables. Check that you wrote name, matric, department with all three names.
Help me fix my tuple unpacking error
Track unique courses with a set
A set automatically removes duplicate items. This is useful for tracking unique values like course codes. Sets also support mathematical operations like finding courses that two students share.
- Add the following code below your tuple print statement:
# Set - unordered, no duplicates
courses = {"CSC101", "MTH101", "PHY101", "CSC101", "MTH101"}
print(f"Unique courses: {courses}") # duplicates removed
more_courses = {"CSC201", "MTH101"}
shared = courses & more_courses # intersection
all_courses = courses | more_courses # union
print(f"Shared courses: {shared}")
print(f"All courses: {all_courses}")
print()
# Dictionary - key:value pairs
records = []
What does this code do?
- courses = {...} creates a set. Even though "CSC101" and "MTH101" appear twice, the set stores each value only once.
- & is the intersection operator. It returns items found in both sets.
- | is the union operator. It combines all items from both sets, keeping no duplicates.
- records = [] creates an empty list that will hold student dictionaries in the next step.
- Save student_records.py and run it again.
- You should see Unique courses: with only three items (duplicates removed), Shared courses: showing {'MTH101'}, and All courses: showing four unique codes.
Set output looks different from expected?
Sets are unordered, so the items may print in a different order each time you run the program. What matters is that duplicates are removed and the correct items appear. If you see five items instead of three in courses, check that you used curly braces {} and not square brackets [].
Help me understand why my set output looks wrong
Exam tip: lists vs tuples vs sets
Your exam may ask you to choose the right data structure. Lists are mutable and ordered. Tuples are immutable and ordered. Sets are mutable but unordered with no duplicates.
If the question says "the data must not change," use a tuple. If it says "no duplicates," use a set. If it says "items can be added or removed in order," use a list.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here is the full student_records.py file at this point:
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
# --- Functions ---
def calculate_grade(score):
"""Take a numeric score, return a letter grade."""
if score >= 70:
return "A"
elif score >= 60:
return "B"
elif score >= 50:
return "C"
elif score >= 40:
return "D"
else:
return "F"
if __name__ == "__main__":
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
# --- Conditionals ---
grade = calculate_grade(percentage)
passed = percentage >= 40
print(f"Grade: {grade}")
print(f"Passed: {passed}")
print()
# --- Data Structures ---
# List - mutable, ordered
student_names = ["Jeffrey", "Ada", "Chidi", "Bola", "Emeka"]
student_names.append("Fatima")
student_names.sort()
print(f"Sorted students: {student_names}")
# Tuple - immutable, ordered
student_info = ("Jeffrey", "CSC/2025/001", "Computer Science")
name, matric, department = student_info # tuple unpacking
print(f"Unpacked: {name}, {matric}, {department}")
# Set - unordered, no duplicates
courses = {"CSC101", "MTH101", "PHY101", "CSC101", "MTH101"}
print(f"Unique courses: {courses}") # duplicates removed
more_courses = {"CSC201", "MTH101"}
shared = courses & more_courses # intersection
all_courses = courses | more_courses # union
print(f"Shared courses: {shared}")
print(f"All courses: {all_courses}")
print()
# Dictionary - key:value pairs
records = []
Your program now stores data in three different structures. Next, you will add loops to process all the student records and list comprehensions to filter them in one line.
Organize Code with Functions and List Comprehensions
Your Student Record Manager now stores data in lists, tuples, sets, and dictionaries. But as your program grows, repeating the same logic in multiple places makes code hard to read and maintain.
Functions let you wrap reusable logic into named blocks that you call whenever you need them. In this step, you'll write functions to calculate averages, display records, and add students. Then you'll use loops and list comprehensions to process all your student data cleanly.
In this step, get ready to:
- Write helper functions for averaging scores, displaying records, and adding students.
- Use loops (for, enumerate, zip, while) to iterate over student records.
- Filter and transform data with list comprehensions.
Write the get_student_average function
You already have calculate_grade() at the top of your file. Now you need a function that calculates the average of a list of scores. This function will be called inside other functions later.
- In student_records.py, find the blank line after the closing else block of calculate_grade.
- Add this new function below it:
def get_student_average(scores):
"""Take a list of scores, return the average as a float."""
total = sum(scores)
count = len(scores)
average = total / count
return average
What does this code do?
- def get_student_average(scores) defines a function that accepts one parameter: a list of numbers.
- sum(scores) adds all numbers in the list. len(scores) counts how many items are in the list.
- return average sends the calculated value back to whatever code called this function.
What are parameters and return values?
A parameter is the variable name inside the parentheses when you define a function (like scores). An argument is the actual value you pass in when you call the function (like [70, 85, 60]).
The return statement is how the function sends its result back to the caller. Without it, the function returns None by default.
- Save student_records.py.
Write display_record and add_student functions
You need two more functions. One prints a student's record in a readable format. The other creates a complete student dictionary and appends it to your records list.
- Below get_student_average, add the display_record function:
def display_record(student_dict):
"""Take a student dictionary and print it formatted."""
print(f"Name: {student_dict['name']}")
print(f"Matric: {student_dict['matric']}")
print(f"Scores: {student_dict['scores']}")
print(f"Average: {student_dict['average']:.1f}")
print(f"Grade: {student_dict['grade']}")
print("-" * 30)
What does this code do?
- student_dict is a dictionary with keys like "name", "matric", and "scores". The function accesses each key with bracket notation.
- :.1f in the f-string formats the average to one decimal place.
- "-" * 30 prints a divider line 30 dashes wide to visually separate records.
- Below display_record, add the add_student function:
def add_student(records, name, matric, scores):
"""Create a student dictionary and append it to records."""
average = get_student_average(scores)
grade = calculate_grade(average)
student = {
"name": name,
"matric": matric,
"scores": scores,
"average": average,
"grade": grade,
}
records.append(student)
return student
What does this code do?
- add_student takes four parameters: the records list, a name, a matric number, and a list of scores.
- It calls get_student_average() and calculate_grade() to compute derived values, then bundles everything into a dictionary.
- records.append(student) adds the new dictionary to the list. The function also returns the dictionary so the caller can use it immediately if needed.
- Save student_records.py.
Seeing an IndentationError?
Make sure all three new functions (get_student_average, display_record, add_student) are at the same indentation level as calculate_grade. They should start at column 1 with no leading spaces. Each function body should be indented by 4 spaces.
Help me fix my indentation in student_records.py
Call the functions and process data with loops and comprehensions
Now you'll put the functions to work. You'll populate your records list by calling add_student() five times, then use different loop patterns to iterate over the data.
- First, add a comment above your if __name__ == "__main__": line. Find that line and add # --- Main Program --- on the line directly above it, with a blank line between the comment and the if statement.
- Scroll down to the line records = [] inside your main block. Add the following code directly below it to populate your records:
add_student(records, "Jeffrey", "CSC/2025/001", [70, 85, 60, 78])
add_student(records, "Ada", "CSC/2025/002", [90, 88, 92, 85])
add_student(records, "Chidi", "CSC/2025/003", [45, 50, 38, 42])
add_student(records, "Bola", "CSC/2025/004", [60, 65, 58, 70])
add_student(records, "Emeka", "CSC/2025/005", [30, 35, 28, 40])
What does this code do?
Each call to add_student() creates a complete student dictionary (with name, matric, scores, average, and grade) and appends it to the records list. After these five calls, records holds five dictionaries.
- Below the five add_student calls, add this code to loop over your records using a for loop and enumerate():
# --- Loops and Iterables ---
print("--- All Student Records ---")
for student in records:
display_record(student)
# Using enumerate
print("--- Student Index ---")
for index, student in enumerate(records):
print(f"{index + 1}. {student['name']} - Grade: {student['grade']}")
print()
What does this code do?
- for student in records iterates through each dictionary in the list, calling display_record() on each one.
- enumerate(records) gives you both the index (starting at 0) and the item at each step. Adding 1 to the index makes it display as a human-friendly numbered list.
- Below the enumerate block, add this code to demonstrate zip() and a while loop:
# Using zip
names = [s["name"] for s in records]
grades = [s["grade"] for s in records]
print("--- Zipped Names and Grades ---")
for name, grade in zip(names, grades):
print(f"{name}: {grade}")
print()
# While loop example
print("--- Counting passing students ---")
count = 0
i = 0
while i < len(records):
if records[i]["average"] >= 40:
count += 1
i += 1
print(f"Students who passed: {count}")
print()
What does this code do?
- zip(names, grades) pairs items from two lists together. The first name matches with the first grade, the second with the second, and so on.
- The while loop keeps running as long as i < len(records) is true. You manually increment i each iteration. Forgetting i += 1 would create an infinite loop.
- count += 1 uses the assignment operator to add 1 to count only when the student's average is 40 or above.
- Finally, add this code below the while loop to use list comprehensions and complete the program:
# --- List Comprehensions ---
top_students = [s["name"] for s in records if s["average"] >= 70]
print(f"Top students (avg >= 70): {top_students}")
grade_map = {s["name"]: s["grade"] for s in records}
print(f"Grade map: {grade_map}")
score_doubles = [score * 2 for score in records[0]["scores"]]
print(f"Jeffrey's scores doubled: {score_doubles}")
print()
print("=== Program Complete ===")
What are list comprehensions?
A list comprehension is a one-line way to build a new list from an existing iterable. The syntax is [expression for item in iterable if condition].
- top_students filters records to only students with an average of 70 or above, extracting just their names.
- grade_map is a dictionary comprehension that maps each student's name to their grade.
- score_doubles takes Jeffrey's scores and creates a new list with each score multiplied by 2.
- Save student_records.py.
- Run the program in your terminal by running:
python3 student_records.py
You should see all student records printed with divider lines, a numbered index list, zipped names and grades, the passing student count, top students, the grade map, and doubled scores.
Seeing a NameError or KeyError?
- A NameError means a function is being called before it's defined. Make sure all four functions (calculate_grade, get_student_average, display_record, add_student) are defined above the if __name__ == "__main__": line.
- A KeyError means a dictionary key is misspelled. Check that your keys match exactly: "name", "matric", "scores", "average", "grade".
Help me debug my student_records.py errors
Trace it: what happens when calculate_grade(75) is called?
Your exam will ask you to trace function calls mentally. Here is how to think through calculate_grade(75):
- Python jumps to the function definition. The parameter score is set to 75 in the function's local scope.
- It checks score >= 70. Since 75 >= 70 is True, it executes return "A".
- The function exits immediately. The remaining elif and else branches are never reached.
- Back at the call site, the value "A" replaces the function call. The local variable score no longer exists outside the function.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here is the complete student_records.py file at this point. Compare your code against it:
# Student Record Manager
# Covers: variables, types, casting, operators, conditionals, loops,
# iterables, data structures, list comprehensions, functions
# --- Functions ---
def calculate_grade(score):
"""Take a numeric score, return a letter grade."""
if score >= 70:
return "A"
elif score >= 60:
return "B"
elif score >= 50:
return "C"
elif score >= 40:
return "D"
else:
return "F"
def get_student_average(scores):
"""Take a list of scores, return the average as a float."""
total = sum(scores)
count = len(scores)
average = total / count
return average
def display_record(student_dict):
"""Take a student dictionary and print it formatted."""
print(f"Name: {student_dict['name']}")
print(f"Matric: {student_dict['matric']}")
print(f"Scores: {student_dict['scores']}")
print(f"Average: {student_dict['average']:.1f}")
print(f"Grade: {student_dict['grade']}")
print("-" * 30)
def add_student(records, name, matric, scores):
"""Create a student dictionary and append it to records."""
average = get_student_average(scores)
grade = calculate_grade(average)
student = {
"name": name,
"matric": matric,
"scores": scores,
"average": average,
"grade": grade,
}
records.append(student)
return student
# --- Main Program ---
if __name__ == "__main__":
print("=== Student Record Manager ===\n")
# --- Variables, Data Types, Casting, Operators ---
student_name = "Jeffrey"
matric_number = "CSC/2025/001"
marks_obtained = 156
total_marks = 200
is_registered = True
# Casting and operators
percentage = (marks_obtained / total_marks) * 100
percentage_int = int(percentage) # casting float to int
print(f"Student: {student_name}")
print(f"Percentage: {percentage}")
print(f"Percentage (int): {percentage_int}")
print(f"Registered: {is_registered}")
print(f"Type of percentage: {type(percentage)}")
print()
# --- Conditionals ---
grade = calculate_grade(percentage)
passed = percentage >= 40
print(f"Grade: {grade}")
print(f"Passed: {passed}")
print()
# --- Data Structures ---
# List - mutable, ordered
student_names = ["Jeffrey", "Ada", "Chidi", "Bola", "Emeka"]
student_names.append("Fatima")
student_names.sort()
print(f"Sorted students: {student_names}")
# Tuple - immutable, ordered
student_info = ("Jeffrey", "CSC/2025/001", "Computer Science")
name, matric, department = student_info # tuple unpacking
print(f"Unpacked: {name}, {matric}, {department}")
# Set - unordered, no duplicates
courses = {"CSC101", "MTH101", "PHY101", "CSC101", "MTH101"}
print(f"Unique courses: {courses}") # duplicates removed
more_courses = {"CSC201", "MTH101"}
shared = courses & more_courses # intersection
all_courses = courses | more_courses # union
print(f"Shared courses: {shared}")
print(f"All courses: {all_courses}")
print()
# Dictionary - key:value pairs
records = []
add_student(records, "Jeffrey", "CSC/2025/001", [70, 85, 60, 78])
add_student(records, "Ada", "CSC/2025/002", [90, 88, 92, 85])
add_student(records, "Chidi", "CSC/2025/003", [45, 50, 38, 42])
add_student(records, "Bola", "CSC/2025/004", [60, 65, 58, 70])
add_student(records, "Emeka", "CSC/2025/005", [30, 35, 28, 40])
# --- Loops and Iterables ---
print("--- All Student Records ---")
for student in records:
display_record(student)
# Using enumerate
print("--- Student Index ---")
for index, student in enumerate(records):
print(f"{index + 1}. {student['name']} - Grade: {student['grade']}")
print()
# Using zip
names = [s["name"] for s in records]
grades = [s["grade"] for s in records]
print("--- Zipped Names and Grades ---")
for name, grade in zip(names, grades):
print(f"{name}: {grade}")
print()
# While loop example
print("--- Counting passing students ---")
count = 0
i = 0
while i < len(records):
if records[i]["average"] >= 40:
count += 1
i += 1
print(f"Students who passed: {count}")
print()
# --- List Comprehensions ---
top_students = [s["name"] for s in records if s["average"] >= 70]
print(f"Top students (avg >= 70): {top_students}")
grade_map = {s["name"]: s["grade"] for s in records}
print(f"Grade map: {grade_map}")
score_doubles = [score * 2 for score in records[0]["scores"]]
print(f"Jeffrey's scores doubled: {score_doubles}")
print()
print("=== Program Complete ===")
Your Student Record Manager is complete. You've used variables, data types, casting, operators, conditionals, loops, iterables, data structures, list comprehensions, and functions all in one connected program. Ready for a bonus challenge? The Secret Mission takes this entire program and restructures it using Object-Oriented Programming.
Secret mission
Refactor to Object-Oriented Programming
Your procedural Student Record Manager works. But what if you could organize all that logic into clean, reusable objects? In this secret mission, you will refactor the entire program into classes, using __init__, self, methods, and inheritance.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your files for exam revision or delete them entirely.
Resources you used:
- The student_records folder on your Desktop (contains student_records.py and student_records_oop.py).
Keep everything running
No action needed. Choose this if you want to keep your files for exam revision and future reference.
- Your student_records folder stays on your Desktop with both Python files intact.
- You can re-run either file at any time with python3 student_records.py or python3 student_records_oop.py.
Pause - I'll come back to this later
Since this project is just local files with no running processes, there is nothing to pause. Your files will sit on disk until you need them again.
- No background processes are running from this project.
- Your files take up minimal disk space and are ready whenever you want to revisit them.
Delete - I don't want to use this again
Remove all project files and start fresh.
- Delete the student_records folder by running this command in your terminal:
rm -rf ~/Desktop/student_records
- Confirm the folder is gone by running:
ls ~/Desktop | grep student_records
If nothing is returned, the folder has been successfully deleted.
That's a Wrap!
That's a Wrap!
Nice work! You just built a complete Student Record Manager in Python, covering every concept on your exam syllabus in one connected program.
You've learned how to:
- Build a working program using variables, data types, casting, operators, conditionals, and loops to store, grade, and display student records.
- Store and manipulate data using lists, tuples, sets, and dictionaries, plus filter and transform data with list comprehensions and dictionary comprehensions.
- Organize code into reusable functions with parameters, return values, and a if __name__ == "__main__": entry point.
- Secret Mission: Refactored everything into an OOP design with classes, inheritance, and methods.
Ready to quiz yourself?