EE1021 Programming for Engineers · Lecture 6 · 2026–2027
try blocks and specific except clausesValueError when an input violates a function contractdef parse_reading(text):
sensor, value = text.split(",")
return sensor, float(value)
print(parse_reading("T2,error"))Before running the code, predict:
float("error") raises ValueError. The program is syntactically valid, but this input cannot be converted.
Pseudocode helps define expected behavior before debugging:
INPUT one record
SPLIT record into sensor ID and value text
CONVERT value text to a number
IF conversion is impossible
REPORT an invalid reading
OTHERWISE
RETURN sensor ID and numeric valueDebugging asks: where does actual behavior first differ from this plan?
| Category | When detected | Typical evidence |
|---|---|---|
| Syntax error | Before execution | SyntaxError, invalid Python grammar |
| Runtime exception | During execution | Traceback and exception type |
| Logic error | After or during execution | Wrong result without an exception |
An exception is an event at runtime. If no matching handler deals with it, normal execution stops and the exception propagates to the caller.
The statement is valid Python. Execution fails because the value does not satisfy the conversion operation.
readings = [20.0, 22.0, 24.0]
average = sum(readings) / (len(readings) - 1)
print(average) # 33.0, but expected 22.0No exception occurs. We need an expected result or an invariant to expose the defect.
Classify each as syntax, runtime, or logic:
print(readings[5]) for a three-item listif voltage > 5.0 print("high")registry["S9"] when S9 is absentCheck: runtime (IndexError), syntax, logic, runtime (KeyError).
Traceback (most recent call last):
File "monitor.py", line 9, in <module>
print(convert(record))
File "monitor.py", line 5, in convert
return float(value_text)
ValueError: could not convert string to float: 'error'Read from the final line upward:
| Evidence | Question it answers |
|---|---|
ValueError |
What kind of failure occurred? |
| conversion message | What operation and value failed? |
monitor.py, line 5 |
Where did it fail? |
convert(record) |
How did execution reach that line? |
A traceback is evidence—not the complete diagnosis. Inspect the data and the intended contract next.
Traceback (most recent call last):
File "summary.py", line 12, in <module>
print(average_reading([]))
File "summary.py", line 7, in average_reading
return sum(values) / len(values)
ZeroDivisionError: division by zeroaverage_reading; the empty list; decide whether empty input is invalid, has a sentinel result, or must be prevented by the caller.
Changing several things at once destroys useful evidence.
values = [20.0, 22.0, 24.0]
expected = 22.0
actual = sum(values) / (len(values) - 1)
print("expected:", expected)
print("actual: ", actual)The first useful debugging question is often: what should this specific input produce?
Temporary output should test a hypothesis. Remove or convert it to a test after the repair.
For larger programs, a debugger can pause execution and inspect the same state without adding prints.
For an average function, test:
| Case | Why it matters |
|---|---|
[20.0, 22.0, 24.0] |
ordinary behavior |
[20.0] |
smallest valid collection |
[] |
empty boundary |
[20.0, "bad"] |
invalid element |
A repair is incomplete until the original failure and nearby cases have been retested.
A report is correct for three sensors but wrong when only one sensor is supplied. What is the most useful next action?
except ExceptionCheck: 3. It isolates the boundary and exposes the first incorrect state.
try and except Change Control Flowtry block.Use exception handling for failures that are expected and recoverable here.
try Block NarrowToo broad
A narrow block makes the handled operation clear and avoids hiding unrelated defects.
try:
sensor, value_text = record.split(",")
value = float(value_text)
except ValueError as error:
print("Invalid record:", error)Both unpacking and conversion can raise ValueError. If the responses should differ, separate the operations and their handlers.
Avoid a bare except: or except Exception: in beginner programs: it can conceal unexpected defects and interrupts.
y |
Operation | Handler | Outcome |
|---|---|---|---|
1 |
5 / y |
not needed | result is 5.0 |
0 |
5 / y |
except ZeroDivisionError |
handler runs |
"abc" |
5 / y |
no matching TypeError handler |
exception propagates |
An except clause handles only compatible exception types.
Write the printed letters in order.
Check: A, B, D, E. The exception skips the remaining statements in try.
try:
sensor, value_text = record.split(",")
value = float(value_text)
limit = limits[sensor]
except ValueError as error:
print("Malformed record:", error)
except KeyError as error:
print("Unknown sensor:", error)
else:
print(sensor, value, limit)The else block runs only when the try block completes without an exception.
Validation asks whether a known condition is acceptable before an operation.
Exception handling responds when an operation cannot complete.
raisedef average_reading(values):
"""Return the average of a non-empty sequence."""
if not values:
raise ValueError("values must not be empty")
return sum(values) / len(values)raise makes a violated contract explicit. The caller can handle the failure where recovery makes sense.
def average_reading(values):
if not values:
raise ValueError("values must not be empty")
return sum(values) / len(values)Should this function print an error and ask for input?
Usually no. The function should report the contract violation with ValueError; the user-interface layer decides how to inform the user or request new input.
def parse_reading(record):
parts = record.split(",")
if len(parts) != 2:
raise ValueError("expected SENSOR,VALUE")
sensor, value_text = parts
try:
value = float(value_text)
except ValueError as error:
raise ValueError("value must be numeric") from error
return sensor, valueThe function validates structure, handles conversion evidence, and returns one predictable tuple.
For parse_reading, state the expected result for:
"T1,23.5""T2,error""missing-comma"Then write one assertion for the valid case and name the exception expected for the invalid cases.
Check: ("T1", 23.5); both invalid records raise ValueError with different messages.
In the lab, you will use this workflow to repair a sensor-data pipeline.