Page 5 of 8~96 min topic

Python only what you need

Debug string scores that compare lexicographically in the score labeler

Page 5 reproduces and repairs the characteristic failure of the threshold score labeler (`scores.py`): string scores that compare lexicographically, or IndentationError that hides a wrong cutoff.

~12 min this pageDebuggingReviewed 2026-08-08

1Learn the idea

Read

Reproduce before you repair

Do not start with a speculative fix for the score labeler. Force the failure on purpose, save the before output, then change one cause at a time. Retries are allowed only for transient conditions—not for bad input that will fail forever on python-only-what-you-need.

Read

Force the real failure

def broken_label(score, threshold):
    return "yes" if score >= threshold else "no"

print(broken_label("9", "50"))

Expected output: yes. That is wrong numerically because 9 is below 50. Both values are strings, so Python compares character order. With "0.9" and numeric 0.5, Python 3 raises TypeError instead; it does not silently compare them. Distinguishing these cases prevents inaccurate debugging advice.

Read

Repair with a reviewable diff

Reject strings at the boundary, then keep labeling numeric:

def require_number(value, name):
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise TypeError(f"{name} must be a number")
    value = float(value)
    if not 0.0 <= value <= 1.0:
        raise ValueError(f"{name} must be between 0 and 1")
    return value

try:
    require_number("0.9", "score[0]")
except TypeError as error:
    print("caught:", error)

Expected output: caught: score[0] must be a number. Do not retry: the same invalid value will fail forever.

Read

Lab notebook: reproduce on command

Store a one-command reproduction for: string scores that compare lexicographically, or IndentationError that hides a wrong cutoff. The command should use scores=[0.2,0.9,0.4], threshold=0.5 or a minimal mutant of it. Paste the failing output into notes/failure-before.txt (or your shell scrollback as copied text). After the fix, paste notes/failure-after.txt and keep both.

Retries belong only on transient faults. If the failure is bad input, a bad allowlist, or a logic bug in the score labeler, retrying will amplify cost without repairing trust around accept or reject a model score using one shared cutoff.

Read

Worked judgment

Classify the failure as prevent, detect, contain, or recover—using this lab’s language, not a generic poster. For python-only-what-you-need, the first fix should usually be detect+prevent at the boundary, because string scores that compare lexicographically, or IndentationError that hides a wrong cutoff is cheaper to stop early than to explain in production prose.

Read

Independent transfer

Reproduce lexical ordering with "100" < "20", explain the result, then design a boundary for integer quantities that rejects strings and booleans. Keep the failing example as a regression test.

ML Python starter

Previous · Next

Go deeper

Before you start

Why this matters

Describe the smallest fixture that triggers string scores that compare lexicographically. Predict the first visible symptom (exception, wrong label, silent empty success). You will compare that prediction with the reproduction below.

In the wild

See how this idea shows up as a product and a company — then come back to the lesson. Skills transfer across vendors.

Check your understanding

Page assessment

Answer from memory. Completion is saved from this evidence, not from opening the next page.

1. Can you reproduce the failure with a one-command fixture?
2. Did you avoid retrying non-transient bad input?
3. Is before/after evidence saved as text (not only a screenshot)?
4. Does the repair restore the metric path toward: boundary labels at 0.49/0.50/0.51 and empty-list positive count 0?

All responses are required.