Python Tutorial / Practice Conditions and Loops with a Score Summary

A score summary combines validation, classification and aggregate calculation. Exclude invalid scores from the statistics while reporting their count so that missing data is visible rather than silently ignored.

Define the data and calculation rules

This exercise assumes an existing list of integers. Valid scores are 0 through 100, and scores of at least 60 pass. Parsing text from CSV or user input is a separate preparation step. Negative values and values above 100 are counted as invalid.

Case Rule
60 Passing score
0 Valid score
-1 or 101 Increment the invalid count
No valid scores Do not calculate an average

For the relevant APIs and platform requirements, see Python: controlflow.

Conditions and automated boundary checks build on the rules demonstrated in Compare Values and Combine Boolean Conditions and Write Automated Tests with unittest and Boundary Cases.

Run the complete score summary

Save the complete code below as scores.py in a separate practice folder, using UTF-8. Run python scores.py in a terminal with your project virtual environment selected. Outside a virtual environment on macOS or Ubuntu, use python3 when that is your interpreter command.

scores = [80, 60, 0, 100, -1, 101]
valid = []
invalid = 0
passed = 0
for score in scores:
    if not 0 <= score <= 100:
        invalid += 1
        continue
    valid.append(score)
    if score >= 60:
        passed += 1
print("valid:", len(valid), "invalid:", invalid)
if valid:
    print(f"average: {sum(valid) / len(valid):.1f}")
    print("passed:", passed)
else:
    print("no valid scores")

Expected output:

valid: 4 invalid: 2
average: 60.0
passed: 3

Follow the counters and denominator

invalid counts rejected inputs; passed counts passing scores only among valid inputs. continue prevents a rejected score from entering valid, so it cannot enter the average’s denominator. Zero is false in a condition but remains a valid score; if score would incorrectly exclude it.

Calculate the average after collecting the valid scores. Testing the collection once before division handles the no-data case without recalculating an average on each iteration. The valid-score count and invalid count should add up to the original input count.

The boundary table can become test input directly. Handle an empty list according to the chosen policy before calculating an average. Check 0, 59 and the pass boundary 60 so that each takes the intended branch. Testing both sides of a boundary exposes an incorrect comparison operator.

Test each boundary and state the assumptions

  1. Use an empty list and check for no valid scores.
  2. Use [59, 60, 61] and check that two scores pass.
  3. Use [-1, 101] and confirm that no average is printed.
  4. Restore the original values and reconcile the counts with the input size.

If the input contract expands beyond integers, decide whether floats are allowed and whether bool should be rejected despite being an int subclass. This example validates ranges under its stated integer-input assumption. Changing the source data type requires expanding validation rather than assuming the range check proves everything.