Calculating an academic grade from student exam marks is the classic demonstration of if-else conditional statements and multi-branch elif decision ladders in Python.
Multi-Condition Decision Trees: By testing scores against sequential cutoffs using comparison operators, programs dynamically categorize numeric scores into letter grades, GPA bands, and pass/fail states. User marks entered via input() must be sanitized with try-except blocks to reject non-numeric strings or out-of-bounds values. For repetitive evaluation across full classrooms, see for loops and lists.
An if-elif-else chain tests expressions sequentially from top to bottom. As soon as one condition evaluates to True, Python executes that block and immediately skips the remainder of the ladder:
# Formal syntax of multi-branch if-elif-else ladder
if primary_condition:
statement_block_1
elif secondary_condition:
statement_block_2
else:
fallback_block
| Score Range | Assigned Grade | Academic Standing | Conditional Expression |
|---|---|---|---|
| 80 – 100 | Grade A | Distinction / Excellent | if marks >= 80: |
| 60 – 79.9 | Grade B | First Class / Good | elif marks >= 60: |
| 40 – 59.9 | Grade C | Second Class / Satisfactory | elif marks >= 40: |
| 0 – 39.9 | Fail | Needs Improvement | else: |
# 1. Standard grade determination using if, elif, and else
def assign_grade(marks: float) -> str:
if marks >= 80:
return "Grade A"
elif marks >= 60:
return "Grade B"
elif marks >= 40:
return "Grade C"
else:
return "Fail"
for score in [85, 68, 42, 33]:
print(f"Marks: {score:>2} -> {assign_grade(score)}")Terminal Output:
Marks: 85 -> Grade A
Marks: 68 -> Grade B
Marks: 42 -> Grade C
Marks: 33 -> Fail
Real-world grading scripts must protect against out-of-range marks (< 0 or > 100) and non-numeric input strings from input():
# 2. Input validation with boundary checks
def evaluate_student_input(user_input: str) -> str:
try:
mark = float(user_input)
except ValueError:
return "Error: Invalid non-numeric input."
if mark < 0 or mark > 100:
return "Error: Marks must be between 0 and 100 inclusive."
if mark >= 90:
return "Grade A+ (Distinction)"
elif mark >= 80:
return "Grade A"
elif mark >= 60:
return "Grade B"
elif mark >= 40:
return "Grade C"
else:
return "Grade F (Fail)"
print(evaluate_student_input("92.5"))
print(evaluate_student_input("105"))
print(evaluate_student_input("abc"))Terminal Output:
Grade A+ (Distinction)
Error: Marks must be between 0 and 100 inclusive.
Error: Invalid non-numeric input.
Flat, chained elif statements prevent deep indentation and represent idiomatic Python:
# 3. Flat elif ladder vs. deeply nested if-else structures
score = 75
if score >= 90:
tier = "Elite"
elif score >= 70:
tier = "Commended"
elif score >= 50:
tier = "Pass"
else:
tier = "Fail"
print("Flat ladder tier:", tier)Terminal Output:
Flat ladder tier: Commended
Python supports inline conditional expressions (ternary operator) using X if condition else Y:
# 4. Ternary conditional expression for compact grading
marks = 88
grade = 'A' if marks >= 90 else 'B' if marks >= 80 else 'C' if marks >= 60 else 'F'
status = "Passed" if marks >= 40 else "Failed"
print(f"Score: {marks} | Grade: {grade} | Outcome: {status}")Terminal Output:
Score: 88 | Grade: B | Outcome: Passed
When grade scales involve many distinct brackets, the standard library bisect module provides an O(log N) lookup:
# 5. Scalable grading via bisect module
import bisect
cutoffs = [40, 60, 70, 80, 90]
grades = ['F', 'D', 'C', 'B', 'A', 'A+']
def get_grade_bisect(score: float) -> str:
return grades[bisect.bisect_right(cutoffs, score)]
for m in [35, 65, 75, 88, 98]:
print(f"Score {m:>2} -> {get_grade_bisect(m)}")Terminal Output:
Score 35 -> F
Score 65 -> C
Score 75 -> B
Score 88 -> A
Score 98 -> A+
Calculating class totals and averages using sum() and len() before applying grading rules:
# 6. Calculating average marks and class grade
marks = [85, 78, 92, 68, 74, 88, 90]
avg = sum(marks) / len(marks)
if avg >= 90:
class_grade = 'A'
elif avg >= 80:
class_grade = 'B'
elif avg >= 70:
class_grade = 'C'
else:
class_grade = 'D'
print(f"Average Marks: {avg:.2f}, Grade: {class_grade}")Terminal Output:
Average Marks: 82.14, Grade: B
Processing multi-subject student records, computing cumulative averages, letter grades, and GPA scale values:
# 7. Production Recipe: Student academic standing report
def academic_report(name: str, scores: dict) -> dict:
avg = sum(scores.values()) / len(scores)
if avg >= 90: letter, gpa = "A+", 4.0
elif avg >= 80: letter, gpa = "A", 3.7
elif avg >= 70: letter, gpa = "B", 3.0
elif avg >= 60: letter, gpa = "C", 2.0
else: letter, gpa = "F", 0.0
return {"student": name, "average": round(avg, 2), "grade": letter, "gpa": gpa}
report = academic_report("Emily", {"Math": 88, "Physics": 92, "CS": 96})
for k, v in report.items():
print(f"{k.capitalize():<9}: {v}")Terminal Output:
Student : Emily
Average : 92.0
Grade : A+
Gpa : 4.0
>=. Evaluating lower thresholds first causes higher scores to match prematurely.
# 8. Common Logic Trap: Inverted condition order
score = 85
# BUG: Checking lower threshold first triggers prematurely!
if score >= 40:
buggy_grade = "C"
elif score >= 80:
buggy_grade = "A"
else:
buggy_grade = "Fail"
print("Buggy evaluation (wrong order):", buggy_grade)Terminal Output:
Buggy evaluation (wrong order): C
Practice conditional grading algorithms, input sanitization, and GPA converters in our companion Jupyter Notebook:
Explore interactive code cells, test edge-case scores (0, 49.9, 50, 89.9, 90, 100), handle invalid inputs gracefully, and run self-validating assertions.
View on GitHub Run in Google ColabRun these unit checks directly in Python to verify grade evaluation mechanics across all boundary conditions:
# 9. Self-verifying unit test suite for grading logic
def grade_test(m):
if m >= 90: return 'A+'
if m >= 80: return 'A'
if m >= 70: return 'B'
if m >= 60: return 'C'
if m >= 50: return 'D'
return 'F'
assert grade_test(100) == 'A+'
assert grade_test(90) == 'A+'
assert grade_test(85) == 'A'
assert grade_test(75) == 'B'
assert grade_test(65) == 'C'
assert grade_test(55) == 'D'
assert grade_test(40) == 'F'
print("All if-else grading unit assertions successfully verified!")Terminal Output:
All if-else grading unit assertions successfully verified!
Checking from highest to lowest (e.g., >= 90, then >= 80) ensures higher scores match their specific bracket before falling into lower thresholds like >= 40.
No. Python evaluates conditions sequentially. As soon as one condition evaluates to True, that block runs and the entire remaining elif/else chain is bypassed.
While syntactically optional, including an else block is best practice to handle scores below the minimum passing threshold (e.g. failing grades).
Convert user input using float(input()) rather than int(). Standard numeric comparisons handle floating-point decimals accurately.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.