[Python-ideas] isinstance(Decimal(), Real) -> False?

Oscar Benjamin oscar.j.benjamin at gmail.com
Wed Aug 28 15:13:10 CEST 2013


On 28 August 2013 13:32, Draic Kin <drekin at gmail.com> wrote:
> On Wed, Aug 28, 2013 at 1:35 PM, Oscar Benjamin <oscar.j.benjamin at gmail.com>
> wrote:
>>
>> The same is true of float but float(Fraction) happily works and so
>> does float(int), complex(int), float(Decimal) and Decimal(float)
>> (depending on the context Decimal can be either a subset or a superset
>> of float). A recent example where I wanted to do this was:
>>
>> def sum_exact(nums):
>>     T = type(nums[0])
>>     return T(sum(map(Fraction, nums)))
>>
>> The above sum function can happily sum anything that is convertible to
>> Fraction (which includes Decimals in Python 3.3). However
>> Decimal(Fraction) fails so you need something like:
>>
>> def sum_exact(nums):
>>     T = type(nums[0])
>>     if issubclass(T, Decimal):
>>         return T.from_decimal(...)
>>     else:
>>        ...
>>
>> This just seems unnecessary to me.
>>
> Maybe it's because float and complex don't care for exactness. On the other
> hand Decimal always represent exactly the value of int and float but it
> cannot represent exactly the value of Fraction(1, 3). But if would be nice
> if one could make a decimal of given precision from fraction or make exact
> decimal representaion of a fraction if it is possible and raise exception
> otherwise.

But that's why the decimal module has the Inexact etc. traps.

Here's a table of coercions that are possible in 3.3. Key (i:int,
F:Fraction, D:Decimal, f:float, c:complex). If Tr is the type of the
row and Tc is the type of the column then X indicates that Tr(Tc) is
always possible and exact and R indicates that rounding may occur:

    i  F  D  f  c
--+---------------
i | X  R  R  R
F | X  X  X  X
D | X     X  X
f | R  R  R  X
c | R  R  R  X  X

There's a little hole in the middle there that makes the real types
not quite inter-operable. It's easy to implement the appropriate
conversion:

def decimal_from_rational(r):
    # Result will be correctly rounded according to the current context.
    # Raises any of the signals Clamped, InvalidOperation, DivisionByZero,
    # Inexact, Rounded, Subnormal, Overflow, or Underflow as appropriate.
    return Decimal(r.numerator) / Decimal(r.denominator)

But it's much more useful if that conversion takes place in Decimal.__new__.


Oscar


More information about the Python-ideas mailing list