Check an Internal Assumption
State an invariant as a relationship at one program point, assert a strong condition where it can first break, and keep internal checks separate from input validation.
Validation checks a program boundary. Inside the program, we instead ask whether its intermediate state still obeys a required relationship.
Name the Relationship That Must Hold
Suppose a loop counts every reading it examines and every available reading it processes:
Every processed reading has already been examined. Therefore this relationship
must be true immediately after processed changes:
processed <= examined
An invariant is a relationship that should be true at a stated point in a program. The loop's meaning requires this one after every processed update.
| Reading visited | examined | processed | processed <= examined |
|---|---|---|---|
| 18 | 1 | 1 | True |
None | 2 | 1 | True |
| 21 | 3 | 2 | True |
| 20 | 4 | 3 | True |
Q1. Choose the required invariant
Which condition expresses the relationship that every processed reading must already have been examined?
Select one choice, then check.
HintAccount for skipped readings
A None value increases examined without increasing processed.
SolutionProcessed is bounded by examined
processed <= examined allows the two counts to be equal or processed to be
smaller. It rejects the impossible state in which more readings were
processed than examined.
Reuse Assert with a Useful Message
Chapter 4 used assert to compare a function result with an independently
reasoned expectation. The same statement can check an internal invariant:
assert processed <= examined, "processed count cannot exceed examined count"
If the condition is false, Python raises AssertionError and shows the message.
Naming both counts preserves more evidence than "something went wrong".
Place the assertion immediately after the update that could first break the rule:
This placement keeps the first bad state beside the code that created it.
Q2. Place the check where the state changes
A loop increments processed in one statement. Where should the invariant
processed <= examined be checked?
Select one choice, then check.
HintStop at the first bad state
Ask which statement changes the left side of the invariant.
SolutionCheck after the processed update
Place the assertion immediately after processed = processed + 1. If that
update creates an impossible count, the failure appears before unrelated work
can obscure it.
Use a Condition Strong Enough to Catch the Defect
An assertion helps only when its condition excludes the unwanted state. This check is true in many broken runs:
assert processed >= 0
It says nothing about whether processed has moved ahead of examined.
processed <= len(readings) can also miss that local defect.
The stronger local condition is:
assert processed <= examined, "processed count cannot exceed examined count"
“Stronger” here does not mean more complicated. It means that the condition rejects the particular unwanted state while remaining true for valid states.
Q3. Repair and guard the running counts
The loop incorrectly adds two processed readings for each available input. Repair the update and add the invariant immediately afterward. The final report should show four examined readings and three processed readings.
Editable Python
Ready to run.
HintRepair before checking
Change the increment from two to one. On the next line, assert
processed <= examined and include the stated message.
SolutionKeep the update and invariant together
Do Not Use Assertions for External Validation
Assertions check rules the program's own logic believes. Python can run with assertions disabled, so essential external validation must not depend on them.
The threshold rule from the previous lesson therefore remains ordinary validation:
Do not replace it with:
assert low <= high
The function must reject reversed caller thresholds consistently. In contrast,
processed > examined means the loop has contradicted its own design.
The earlier mean contract also remains unchanged. Empty or all-unavailable
readings return None. An assertion that readings must be non-empty would not
check an internal invariant; it would erase a legitimate input case.
An invariant names a relationship that must hold at a particular point in the program. Check it with a strong assertion immediately after the update that could break it, and include a message that preserves local evidence. Keep assertions for internal defects; external invalid input still needs ordinary validation and a reliable rejection policy.