Trap Decimal division by zero in a validation helper
Python can trap Decimal division by zero in a validation helper by using a copied local context with DivisionByZero trapped, then catching that specific exception and returning a structured failure. With that trap disabled, Decimal division by zero produces Infinity and sets a context flag; a validator that returns the arithmetic result could mistakenly treat that non-finite value as valid.
The literal input is a mapping with numerator 10 and denominator 0. The first calculation explicitly disables the DivisionByZero trap in a local context, making the unwanted Infinity visible without changing the surrounding context. The helper then creates another local context, enables ctx.traps[DivisionByZero], and performs the same operation. The signal raises DivisionByZero, which the helper converts into {'ok': False, 'error': 'zero_denominator'}. A nonzero denominator follows the normal path and returns a Decimal result.
Catching DivisionByZero intentionally covers only this contract violation. A production validator may also need explicit rules for invalid text, overflow, precision, rounding, and non-finite inputs. Do not use a broad except that turns unrelated programming errors into validation failures. localcontext, context traps, and DivisionByZero are standard-library features available in Python 3.4 and later.
The decimal signals and traps documentation explains how trapped signals raise exceptions, and the DivisionByZero documentation identifies this signal.
AI assistance disclosure: This article was prepared with AI assistance and checked with the shown synthetic example.
from decimal import Decimal, DivisionByZero, localcontext
record = {"numerator": Decimal("10"), "denominator": Decimal("0")}
with localcontext() as ctx:
ctx.traps[DivisionByZero] = False
unchecked = record["numerator"] / record["denominator"]
def validate_ratio(numerator, denominator):
try:
with localcontext() as ctx:
ctx.traps[DivisionByZero] = True
return {"ok": True, "value": numerator / denominator}
except DivisionByZero:
return {"ok": False, "error": "zero_denominator"}
result = validate_ratio(record["numerator"], record["denominator"])
valid_result = validate_ratio(Decimal("10"), Decimal("2"))
assert record == {"numerator": Decimal("10"), "denominator": Decimal("0")}
assert unchecked == Decimal("Infinity")
assert result == {"ok": False, "error": "zero_denominator"}
assert valid_result == {"ok": True, "value": Decimal("5")}
print("input:", record)
print("unchecked:", unchecked)
print("validated:", result)
print("nonzero denominator:", valid_result)
input: {'numerator': Decimal('10'), 'denominator': Decimal('0')}
unchecked: Infinity
validated: {'ok': False, 'error': 'zero_denominator'}
nonzero denominator: {'ok': True, 'value': Decimal('5')}