Skip to content

Exception handling

Handle known Python failures without concealing bad financial data, separate recovery from publication policy, and release resources safely.

Exception handling is the mechanism a program uses to respond when an operation raises an exception: handle a known failure, let it propagate to a caller, or release resources before leaving. In a quant pipeline, that decision determines whether malformed input is visibly rejected or quietly contaminates a calculation.
In Python, raising an exception interrupts the current operation. Execution searches for a matching handler; it does not resume at the failed statement after the handler finishes. An exception can signal a failed conversion, unavailable file or violated function contract. A normal business state, such as an empty order queue, can usually be represented and tested directly without raising an exception.

Catch the failure you can explain

Suppose three fictional whole-share quantities arrive as text. This example stages parseable values separately from records requiring investigation:

texts = ["100", "bad", "105"] accepted = [] quarantined = [] for text in texts: try: quantity = int(text) except ValueError: quarantined.append(text) else: accepted.append(quantity) print(accepted) # [100, 105] print(quarantined) # ['bad']
int("bad") raises ValueError. The handler preserves the offending text and the loop proceeds to "105". There are two accepted integers and one quarantined string. No zero has been invented to stand in for missing financial information.
Only the conversion belongs inside try. The else branch runs when it succeeds, keeping failures in later processing outside this conversion handler. If appending an accepted record fails, that failure should remain visible rather than be mislabelled as malformed input. The Python language reference defines these control-flow rules.
Text quantities 100 and 105 parse into accepted integers; bad raises ValueError and is quarantined. Publication remains a separate policy decision.
Text quantities 100 and 105 parse into accepted integers; bad raises ValueError and is quarantined. Publication remains a separate policy decision.
Fictional staging example: accepted [100, 105], quarantined ['bad']. A complete-data requirement still prevents publication.

Recovering does not mean approving the data

Quarantining is useful when records can be isolated safely and investigated. It is unsuitable as permission to value a portfolio with an omitted position. A strict batch boundary can instead reject the staged result:

if quarantined: raise ValueError("batch rejected: unparsed quantities") # Raises ValueError: batch rejected: unparsed quantities
Here the exception stops that execution path unless a caller handles it. Keep publication downstream of successful validation; catching this error merely to continue would defeat the rule. A different system might permit partial results with explicit completeness flags, but that is a separate, documented policy. Parsing also does not validate economic meaning: int("-1") succeeds, while whether a negative quantity is permitted depends on the field's contract.
Choose a handler only when you know what recovery means. A bare except: catches even interruption signals such as KeyboardInterrupt. Catching Exception is narrower, but still broad enough to hide unrelated defects if it simply continues. For this parser, except ValueError leaves an unexpected TypeError visible. If recording the rejected item itself fails, allow that failure to propagate too; the original parsing failure remains available as exception context. Use structured logging to retain record identifiers and useful diagnostics without exposing sensitive payloads.

Cleanup is a different responsibility

A finally clause runs as Python leaves the try statement, including when an exception propagates. It is for cleanup, not evidence that processing succeeded. For files, prefer with open(...) as file:: the file is closed when the managed block exits, including on a parsing error. A context manager's exact behavior depends on its contract; with does not universally suppress exceptions or undo earlier writes. Avoid returning from finally, which can discard a pending exception.
A useful unit test checks successful input, a recoverable rejection, and an unexpected failure. Also test failure of the recovery step itself. Keeping the process alive is not sufficient if it has lost the information needed to trust its output.
For a worked introduction to parsing, validation and managed file access, see Files and Exceptions (free account; sign-in required).

Sources

The examples use the standard library and were checked with CPython 3.14.4.

Last updated
  • python
  • exceptions
  • control flow
  • data quality
  • resource management
← Back to the glossaryBack to top ↑