decimal module
Monty’s decimal is a port of CPython’s pure-Python _pydecimal with the behaviour of the C _decimal
module CPython actually ships: arithmetic results, the flags each operation sets, which signal a trapped
operation raises and its [<class 'decimal.DivisionByZero'>] message all follow _decimal.
Decimal, Context, localcontext(), getcontext() / setcontext(), the three template contexts,
IEEEContext(), DecimalTuple, every signal class and every constant are available.
- There is one current context per session, not per thread or per
contextvarscontext.localcontext()andsetcontext()work as in CPython, and the current context persists across REPL feeds and snapshots like global variables do. ctx.flagsandctx.trapsreturn a new mapping object on every access, soctx.flags is ctx.flagsisFalse; the mappings read and write through to the context, so everything else behaves the same. Their type prints as<class 'SignalDict'>(CPython:<class 'abc.SignalDict'>) and is not acollections.abc.MutableMapping.keys(),values()anditems()return lists rather than views. A mapping keeps its context alive, so it stays usable after the context is gone, where CPython 3.14.9+ raisesValueError: invalid signal dict(as incopy.deepcopy(ctx).flags[Inexact]).Contextobjects cannot be pickled (__reduce__is absent);copy.copy()andcopy.deepcopy()work.
DecimalandContextcannot be subclassed (Monty has no class inheritance).- A coefficient (or NaN payload) longer than 4300 digits is rejected when a
Decimalis built from astr,intor tuple, withValueError: Exceeds the limit (4300 digits) for a Decimal coefficient: value has N digits. The same applies to anintoperand in arithmetic (Decimal(1) + 10**5000). CPython has no such limit. Results computed under a largeprecare not capped, but materializing one past the memory limit raisesMemoryError. hash()values differ from CPython’s, as Monty’sintandfloathashes do; equal numbers still hash alike (hash(Decimal('1.5')) == hash(1.5),hash(Decimal(2)) == hash(2)), except that an integralDecimalwith more than 5000 digits does not hash like the equalint.- A trapped signal’s exception carries its message as a string:
exc.argsis("[<class 'decimal.DivisionByZero'>]",)where CPython’s is a one-element tuple holding a list of classes.str(exc)matches. Decimal.from_floatandDecimal.from_numbercan only be called in place (Decimal.from_float(0.1)); reading them as attributes (getattr(Decimal, 'from_float'),f = Decimal.from_float) raisesAttributeError, as for Monty’s other builtin class methods.Decimal.as_tuple()returns a plain tuple subclass whose type is notdecimal.DecimalTuple(isinstance(d.as_tuple(), DecimalTuple)isFalse); thesign,digitsandexponentfields work.
Decimal.__format__(spec, override)checks thatoverrideis a dict but ignores itsthousands_sep,decimal_pointandgroupingkeys.
json.loads(s, parse_float=Decimal) works (see json.md); json.dumps rejects a Decimal
with TypeError: Object of type Decimal is not JSON serializable, as CPython does.