Skip to main content

Module 2 — Functions, contracts and errors

EDU-PYT-201 · Module 2 of 4 · Estimated effort: 2 hours including practice

Before you begin: Complete Module 1 or demonstrate its evidence criteria. Use the course environment and downloads.

Outcomes​

Define a function contract; validate numerical boundaries; handle errors without silently changing the meaning of input.

Explain and demonstrate​

A small validation function is a good teaching unit because its behaviour can be stated precisely. The supplied score function converts a value to a floating-point number and accepts only values from 0 through 100 inclusive. Values outside the range and nonnumeric strings are rejected. The special value NaN also fails the bounded comparison. A missing or incompatible object can raise a type error, which a caller must handle deliberately.

Returning zero for every invalid value is tempting because it lets processing continue, but it changes the data. A learner who typed “eighty” would be recorded as scoring zero. Error handling should preserve the distinction between a legitimate zero and an invalid record. Decide whether the application stops, reports the row or collects errors; do not let a broad exception handler choose the policy accidentally.

Worked example: boundary classes​

InputExpected behaviourWhy it matters
"0"0.0Lower boundary is valid
"100"100.0Upper boundary is valid
"101"ValueErrorAbove the permitted range
"oops"ValueErrorCannot represent a number
"nan"ValueErrorNot a usable bounded score

A contract must also state what it does not promise. This fixture accepts decimal scores and numeric strings. An institution requiring integer marks or locale-specific decimal notation would need a different documented rule. Do not claim the example implements an unknown institution’s marking policy.

Lab — make rejection teachable​

Setup: Use the course lab.py in a local folder. All data are fictional.

  1. Run python lab.py contracts; expect 0.0 100.0.
  2. Run python lab.py test; six tests should pass.
  3. Add cases immediately below and above the boundaries, and explain whether decimal values are permitted by this contract.
  4. Write a caller that catches a validation error and records a neutral message identifying the failed field. Avoid printing confidential raw data.
  5. Explain why except Exception: return 0 is inappropriate here.
  6. Design a hint ladder for a learner who rejects 100 because they used a strict upper-bound comparison.

Fault injection: Replace <= 100 with < 100 in a copy and show that the upper-bound test fails. Recovery: Restore the inclusive comparison and rerun the suite.

Expected observations: A valid zero remains distinguishable from invalid input. Evidence: Contract, boundary cases, failure/recovery record and feedback. Cleanup: Remove the mutant copy; retain the corrected function and synthetic test inputs.

Common pitfalls and teaching decisions​

Checking only one typical value misses the boundaries. Catching too broad an exception can hide programming defects. A user-friendly message should not erase the exception’s cause from authorized diagnostic evidence. Discuss which information belongs in learner-facing feedback and which belongs in a restricted technical log.

Retrieval and reflection​

Why is converting invalid input to zero a data-quality problem?

It makes an invalid record indistinguishable from a genuine zero and may alter an assessment outcome.

Does this function enforce integer-only marking?

No. It accepts decimal numeric values within the range. A different policy needs an explicit contract and tests.

Official references​

Python errors and exceptions · Python floating-point arithmetic · Python built-in float.

Ask about facilitated enrolment