decimal.InvalidOperation in python

Pigna picture Pigna · Dec 31, 2015 · Viewed 13.2k times · Source

I was testing my code and I thought that this piece of code was correct:

while True:
    try:
        p = Decimal(raw_input(...))
        if ...condition... : break
        else: raise ValueError
    except ValueError:
        print "Error! ..."

but it's not, since when I input "a", this is what I get:

File "multiple.py", line 28, in <module>
  precision = Decimal(raw_input(...))
File "/usr/lib/python2.7/decimal.py", line 548, in __new__
  "Invalid literal for Decimal: %r" % value)
File "/usr/lib/python2.7/decimal.py", line 3872, in _raise_error
  raise error(explanation)
decimal.InvalidOperation: Invalid literal for Decimal: 'a'

ValueError does not catch InvalidOperation. I don't want the program to stop because of that, I want it to keep asking for input until it satisfies the condition. How do I do it?

Answer

Martijn Pieters picture Martijn Pieters · Dec 31, 2015

The signal exceptions in the decimal module are all subclasses of the decimal.DecimalException exception class. You can catch any of the following exceptions to deal with the InvalidOperation exception, from the specific to the (very) generic:

decimal.InvalidOperation
decimal.DecimalException
ArithmeticError
Exception
BaseException

ValueError is not in that hierarchy, but catching Exception would also catch ValueError since it is a subclass. Generally speaking, you rarely want to catch BaseException since that catches all possible exceptions, including SystemExit and MemoryError.

You can catch multiple exceptions in the same handler:

from decimal import Decimal, DecimalException

while True:
    try:
        p = Decimal(raw_input(...))
        if ...condition... : break
        else: raise ValueError
    except (ValueError, DecimalException):
        print "Error! ..."

would catch both your original ValueError exceptions, and all signal exceptions raised by the decimal module.