Is there really something here that needs to be fixed? It's very common for modules to define their own root exception class. And usually people who care about these kinds of exceptions just catch whatever exception is raised by the combination of argument they care about (e.g. calling float() with a string argument). The Decimal module already doesn't play all that much by the same rules as other modules (e.g. it doesn't participate in the numeric tower) so people trying to write algorithms independent from whether the numbers they're processing are floats, fractions or Decimals are already in a lot of pain, I imagine -- and the best solution is probably to just stick with Decimal (numerical specialists would cringe at attempts to write code without knowing how the arithmetic is done in detail anyways). If there's anything in this area that bugs me it would be that I'd worry that some obscure invalid input string to float() might not raise ValueError but something else (e.g. OverflowError -- while I cannot reproduce this, I've seen lots of code that catches that). But in Decimal I would expect this all to be specified by the standard, so I see no need to lose sleep there. On Tue, May 24, 2016 at 5:26 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 25 May 2016 at 02:56, Guido van Rossum <gvanrossum@gmail.com> wrote:
If it's the right thing to do we should do it, and consider how to do it without breaking too much code too soon (or without clear indication of failure). I don't think a PEP is needed unless there's a lot of discussion about alternatives or disagreement.
Recapping the thread, the specific problem Steven raised was that catching ValueError will handle "float('not-a-valid-float')", but not "Decimal('not-a-valid-float')", as the latter raises decimal.InvalidOperation, which inherits from ArithmeticError rather than ValueError.
There are 3 possible ways of changing that:
- make ArithmeticError a subclass of ValueError - make decimal.InvalidOperation inherit from both ArithmeticError & ValueError - raise a subclass of InvalidOperation that also inherits from ValueError for decimal string conversions
The last one is clearly the lowest risk and lowest impact way to allow ValueError to be used to catch decimal string conversion problems, so in the absence of any other considerations, I'd just say "Let's do that".
However, what came up in the course of the discussion is that those of us participating in the thread don't actually know the original rationale for ArithmeticError being entirely distinct from ValueError, rather than being a subclass of it, which means there are other cases where folks may be expecting ValueError to catch all conversion errors, but it may in fact be missing some. As a toy example:
def to_float(x): ... try: ... return float(x) ... except ValueError: ... return float("nan") ... to_float("not-a-float") nan to_float(10**1000) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in to_float OverflowError: int too large to convert to float from fractions import Fraction class LazyFraction: ... def __float__(self): ... return float(Fraction(1, 0)) ... to_float(LazyFraction()) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in to_float File "<stdin>", line 3, in __float__ File "/usr/lib64/python3.5/fractions.py", line 186, in __new__ raise ZeroDivisionError('Fraction(%s, 0)' % numerator) ZeroDivisionError: Fraction(1, 0)
Before this thread, I would have said that the above "to_float()" function would reliably return either the converted value or NaN in the absence of coding bugs in a __float__ method implementation, but the OverflowError and ZeroDivisionError cases above show that I would have been wrong about that, and a more comprehensive exception clause would be "except (ValueError, ArithmeticError):".
If you rule out turning ArithmeticError into a ValueError subclass in 3.6+, then we can go back to looking specifically at the decimal string conversion behaviour. However, if you thought the builtin exception hierarchy change was an idea worth considering further, then it would address decimal string conversions as a side effect (since those are already an ArithmeticError subclass).
Regards, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
-- --Guido van Rossum (python.org/~guido)