Editor

Student Grade Manager in Python

Intermediate · Useful tools · about 60 minutes to build · 128 lines

Enter each student's marks in five subjects and get a ranked report table, a grade for every subject and a report card for any student.

The program

Press Run and answer its questions in the box that appears under the code.

student_grade_manager.py
"""A student grade manager: marks, average, grade, result and a report table."""
# Subject name -> short name for the table
SUBJECTS = {
"English": "Eng",
"Maths": "Mat",
"Science": "Sci",
"Social Science": "SSt",
"Computer Science": "CS",
}
MAX_MARK = 100
PASS_MARK = 33
# Lowest mark for each grade, in the style of the CBSE nine-point scale
GRADES = [(91, "A1"), (81, "A2"), (71, "B1"), (61, "B2"), (51, "C1"),
(41, "C2"), (33, "D"), (21, "E1"), (0, "E2")]
MENU = "1) Add student 2) Report table 3) Report card 4) Quit"
# Working out results
def grade_for(mark):
"""Return the grade for a mark or an average."""
for lowest, grade in GRADES:
if mark >= lowest:
return grade
return GRADES[-1][1]
def total_marks(student):
"""Add up a student's marks in every subject."""
return sum(student["marks"].values())
def summary(student):
"""Return (total, average, grade, result) for one student."""
total = total_marks(student)
average = total / len(SUBJECTS)
failed = [s for s, mark in student["marks"].items() if mark < PASS_MARK]
result = "Fail (" + ", ".join(failed) + ")" if failed else "Pass"
return total, average, grade_for(average), result
# Asking for data
def read_mark(subject):
"""Ask until the user types a whole mark from 0 to MAX_MARK."""
while True:
text = input(f" {subject} (0-{MAX_MARK}): ").strip()
if text.isdecimal() and int(text) <= MAX_MARK:
return int(text)
print(f" Please type a whole number from 0 to {MAX_MARK}.")
def add_student(students):
"""Ask for a name and a mark for every subject, then store them."""
name = input("Student name: ").strip()
if not name:
print(" A name is needed. Nothing added.")
return
marks = {subject: read_mark(subject) for subject in SUBJECTS}
students.append({"name": name, "marks": marks})
total, average, grade, result = summary(students[-1])
print(f" Added {name}: {total} marks, {average:.1f}%, grade {grade}, {result}")
def choose_student(students):
"""Show the names with numbers and return the student picked."""
names = [f"{n}) {student['name']}" for n, student in enumerate(students, 1)]
print(" " + " ".join(names))
while True:
text = input(f"Which student (1-{len(students)})? ").strip()
if text.isdecimal() and 1 <= int(text) <= len(students):
return students[int(text) - 1]
print(f" Please type a number from 1 to {len(students)}.")
# Reports
def show_table(students):
"""Print every student ranked by total, with the class average."""
header = "".join(f"{short:>5}" for short in SUBJECTS.values())
print(f" {'Rank':<6}{'Name':<14}{header} Total Avg % Grade Result")
ranked = sorted(students, key=total_marks, reverse=True)
for rank, student in enumerate(ranked, start=1):
total, average, grade, result = summary(student)
marks = "".join(f"{mark:>5}" for mark in student["marks"].values())
print(f" {rank:<6}{student['name']:<14}{marks}"
f"{total:>7}{average:>7.1f} {grade:<7}{result}")
all_marks = sum(total_marks(student) for student in students)
print(f" Class average: {all_marks / (len(students) * len(SUBJECTS)):.1f}%")
def show_report_card(student):
"""Print one student's marks and grade in every subject."""
total, average, grade, result = summary(student)
print(f" Report card: {student['name']}")
for subject, mark in student["marks"].items():
print(f" {subject:<18}{mark:>5} {grade_for(mark)}")
print(f" {'Total':<18}{total:>5} out of {MAX_MARK * len(SUBJECTS)}")
print(f" {'Average %':<18}{average:>5.1f} {grade}")
print(f" Result: {result}")
def main():
"""Run the menu until the user quits."""
students = []
print("Student grade manager")
while True:
print()
print(MENU)
choice = input("Choose 1-4: ").strip()
if choice == "1":
add_student(students)
elif choice in ("2", "3") and not students:
print(" No students yet. Choose 1 to add one.")
elif choice == "2":
show_table(students)
elif choice == "3":
show_report_card(choose_student(students))
elif choice == "4":
print("Goodbye.")
break
else:
print(" Please choose a number from 1 to 4.")
if __name__ == "__main__":
main()

Open it in the full editor to save it, share it and keep building.

Sample run

What the program printed, and what was typed (in yellow).

Student grade manager

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 1
Student name: Asha Rao
  English (0-100): 78
  Maths (0-100): 91
  Science (0-100): 66
  Social Science (0-100): 85
  Computer Science (0-100): 94
  Added Asha Rao: 414 marks, 82.8%, grade A2, Pass

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 1
Student name: Rohan Mehta
  English (0-100): 55
  Maths (0-100): 105
  Please type a whole number from 0 to 100.
  Maths (0-100): 45
  Science (0-100): 30
  Social Science (0-100): 62
  Computer Science (0-100): 70
  Added Rohan Mehta: 262 marks, 52.4%, grade C1, Fail (Science)

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 1
Student name: Meera Iyer
  English (0-100): 92
  Maths (0-100): 88
  Science (0-100): 95
  Social Science (0-100): 79
  Computer Science (0-100): 99
  Added Meera Iyer: 453 marks, 90.6%, grade A2, Pass

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 2
  Rank  Name            Eng  Mat  Sci  SSt   CS  Total  Avg %  Grade  Result
  1     Meera Iyer       92   88   95   79   99    453   90.6  A2     Pass
  2     Asha Rao         78   91   66   85   94    414   82.8  A2     Pass
  3     Rohan Mehta      55   45   30   62   70    262   52.4  C1     Fail (Science)
  Class average: 75.3%

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 3
  1) Asha Rao  2) Rohan Mehta  3) Meera Iyer
Which student (1-3)? 2
  Report card: Rohan Mehta
  English              55  C1
  Maths                45  C2
  Science              30  E1
  Social Science       62  B2
  Computer Science     70  B2
  Total               262  out of 500
  Average %          52.4  C1
  Result: Fail (Science)

1) Add student  2) Report table  3) Report card  4) Quit
Choose 1-4: 4
Goodbye.

How it is built

1. Subjects and grade bands

Each subject has a short name for the table headings. GRADES lists the lowest mark for each grade from the top down, in the style of the CBSE nine-point scale, and 33 is the pass mark.

# Subject name -> short name for the table
SUBJECTS = {
    "English": "Eng",
    "Maths": "Mat",
    "Science": "Sci",
    "Social Science": "SSt",
    "Computer Science": "CS",
}
MAX_MARK = 100
PASS_MARK = 33
# Lowest mark for each grade, in the style of the CBSE nine-point scale
GRADES = [(91, "A1"), (81, "A2"), (71, "B1"), (61, "B2"), (51, "C1"),
          (41, "C2"), (33, "D"), (21, "E1"), (0, "E2")]
MENU = "1) Add student  2) Report table  3) Report card  4) Quit"

2. Finding a grade

The bands go from highest to lowest, so the first band the mark reaches is its grade. The same function grades one subject or a whole average.

def grade_for(mark):
    """Return the grade for a mark or an average."""
    for lowest, grade in GRADES:
        if mark >= lowest:
            return grade
    return GRADES[-1][1]

3. A student's summary

One function works out the total, the average, the grade and the result, so the table and the report card always agree. Any subject under 33 makes the result a fail and is named in it.

def summary(student):
    """Return (total, average, grade, result) for one student."""
    total = total_marks(student)
    average = total / len(SUBJECTS)
    failed = [s for s, mark in student["marks"].items() if mark < PASS_MARK]
    result = "Fail (" + ", ".join(failed) + ")" if failed else "Pass"
    return total, average, grade_for(average), result

4. Reading a mark

isdecimal() accepts whole numbers only, so -1, 7.5 and abc are refused before int() runs.

def read_mark(subject):
    """Ask until the user types a whole mark from 0 to MAX_MARK."""
    while True:
        text = input(f"  {subject} (0-{MAX_MARK}): ").strip()
        if text.isdecimal() and int(text) <= MAX_MARK:
            return int(text)
        print(f"  Please type a whole number from 0 to {MAX_MARK}.")

5. The ranked table

sorted(students, key=total_marks, reverse=True) puts the highest total first, and the position in that list is the rank. Fixed widths such as :>5 keep the columns in line.

def show_table(students):
    """Print every student ranked by total, with the class average."""
    header = "".join(f"{short:>5}" for short in SUBJECTS.values())
    print(f"  {'Rank':<6}{'Name':<14}{header}  Total  Avg %  Grade  Result")
    ranked = sorted(students, key=total_marks, reverse=True)
    for rank, student in enumerate(ranked, start=1):
        total, average, grade, result = summary(student)
        marks = "".join(f"{mark:>5}" for mark in student["marks"].values())
        print(f"  {rank:<6}{student['name']:<14}{marks}"
              f"{total:>7}{average:>7.1f}  {grade:<7}{result}")
    all_marks = sum(total_marks(student) for student in students)
    print(f"  Class average: {all_marks / (len(students) * len(SUBJECTS)):.1f}%")

Make it bigger

  • Give students with the same total the same rank.
  • Save the class to a CSV file and load it when the program starts.
  • Show the top scorer in each subject under the table.
  • Let the teacher choose the subjects at the start.

What it practises