1
Error Handling with try-except
▶When a Python program encounters an error at runtime, it raises an exception — a signal that something unexpected has occurred. Understanding how to catch, inspect, and raise exceptions is essential for writing robust engineering scripts that handle real-world data gracefully.
- What Is an Exception?
- Python raises an exception object when an error condition occurs. Rather than silently producing a wrong answer, Python creates an object describing what went wrong and where, giving you the opportunity to respond to it programmatically.
- An unhandled exception prints a traceback and stops execution immediately. The traceback shows the call stack at the moment of failure, which is useful for debugging but undesirable in production scripts that must keep running.
- Exceptions are organized in a class hierarchy; catching a parent class also catches its subclasses. For example, catching
OSErrorwill also catchFileNotFoundErrorandPermissionError, since both are subclasses ofOSError. - Basic try-except Structure
- Code inside the
tryblock executes normally until an exception is raised. As soon as an exception occurs, Python stops executing the remaining lines in thetryblock and looks for a matchingexceptclause. - If an exception matches the specified type, the
exceptblock executes instead of crashing. This lets your program respond to the error — for example, by printing a message, using a default value, or skipping a bad record. - Multiple
exceptclauses can handle different exception types separately. Listing specific exception types before more general ones ensures each error kind receives the most appropriate response.try: value = int(user_input) except ValueError: print("Input is not a valid integer.") except ZeroDivisionError: print("Cannot divide by zero.") - The
elseandfinallyClauses - The
elseblock executes when thetryblock completes without raising an exception. Placing success-path code inelserather than at the end of thetryblock makes it clear that this code only runs when no error occurred. - The
finallyblock always executes, making it ideal for releasing resources. Whether an exception was raised or not,finallyruns — ensuring file handles are closed, connections are released, and cleanup always happens.try: f = open("data.csv") data = f.read() except FileNotFoundError: print("File not found.") else: print("File read successfully.") finally: print("Cleanup complete.") - Both
elseandfinallyare optional and can be used together or independently. Use whichever combination matches the logic your script requires — they are not mutually dependent. - Accessing Exception Information
- Use
except ExceptionType as eto capture the exception instance. The variableeholds the actual exception object, giving you programmatic access to details about what went wrong. str(e)returns the human-readable error message associated with the exception. Printing or loggingstr(e)alongside context information makes diagnosing problems far easier than a bare "an error occurred" message.try: result = 10 / 0 except ZeroDivisionError as e: print(f"Caught an error: {e}")- The exception object may carry additional attributes relevant to the specific error type. For instance,
OSErrorexposeserrnoandstrerrorattributes that provide machine-readable and human-readable descriptions of the operating-system-level error. - Raising Exceptions
- Use
raise ExceptionType(message)to raise a specific exception with a description. Raising exceptions deliberately lets you enforce preconditions and communicate clearly to callers when your function receives invalid input.def compute_flow(area, velocity): if area <= 0: raise ValueError(f"Area must be positive, got {area}") return area * velocity - Re-raise a caught exception with a bare
raisestatement to propagate it after logging. This pattern lets an intermediate layer record diagnostic information without swallowing the exception, preserving the original traceback for higher-level handlers. - Custom exception classes can be created by subclassing
Exceptionfor domain-specific errors. A class likeSensorReadErrororInvalidMaterialErrormakes error handling code more readable and allows callers to catch only errors relevant to their domain. - Practical Error Handling in Engineering Scripts
- Validate inputs at the boundary of your script using try-except before processing begins. Catching bad data — such as non-numeric values in a CSV column — early prevents cascading failures deep inside calculation functions where errors are harder to interpret.
- Log caught exceptions with enough context to identify the source of the problem. Include the filename, row number, variable name, or sensor ID alongside the error message so that post-run debugging does not require re-running the entire job.
- Design error handling so the script can continue processing remaining data after a recoverable error. Wrapping the processing of each data record in its own try-except block allows the script to skip bad records and report them at the end, rather than halting on the first failure.
errors = [] results = [] for i, record in enumerate(dataset): try: results.append(process(record)) except ValueError as e: errors.append(f"Row {i}: {e}") print(f"Processed {len(results)} records with {len(errors)} errors.")
NotesExplains Python's exception handling model and demonstrates how to use try-except blocks to build resilient engineering scripts that recover gracefully from runtime errors. Emphasise to students that good error handling is not about suppressing errors — it is about responding to them intentionally. Encourage the habit of catching specific exception types rather than bare <code>except:</code> clauses, which can accidentally hide bugs.