Coercing two numbers without coerce()

Steven D'Aprano steve at pearwood.info
Wed Dec 10 22:35:12 EST 2014


On Wed, 10 Dec 2014 20:27:13 -0200, Luciano Ramalho wrote:

> Python 3 dropped the coerce() built-in, but I have a situation where I'd
> love to use it.
> 
> I have two numbers A, B and I need to get the value of A coerced to the
> type of A+B. This is for a generator function that will produce a series
> similar to what itertools.count does.

Let me see if I understand... you have a generator function which takes 
two arguments. For the purpose of this question, you don't actually care 
about A+B, but you want to know what type they will be so that the 
generator can return a bunch of values of that same type.

There are two ways of telling what the type of A+B will be, and only one 
of them works.

The way that doesn't work is to try to guess the result in advance. Note 
carefully that I use type(), not isinstance(), since subclasses can do 
anything they like including returning radically different types.

But for the following built-in and standard numeric types:

    int, float, complex, decimal.Decimal, fractions.Fraction


we can predict the following coercions:

    # X must be in the above list, *excluding* subclasses
    int + X --> type of X
    float + complex --> complex
    Decimal + float --> raise exception
    Fraction + float --> float
    Fraction + complex --> complex
    etc.


Whew! Not fun. And it doesn't deal with subclasses, since they could 
return any arbitrary type. And don't forget that the reversed arguments 
do not necessarily return the same type!

Really, the only way to be sure what A + B will return is to actually 
perform it and see. That will then allow subclasses to do the right thing.

the_type = type(A + B)

Now that you have the type, you can use it in you generator:

    # for example
    for i in range(100):
        yield the_type(A + i)



> I know I can do type(A+B)(A), or A+B-B, but both alternatives are ugly
> and perform needless arithmetic.

The first is not needless, since actually adding A + B is the only way to 
find out what type A+B is in full generality.

Do not use A+B-B, since that is *not* numerically equivalent to A. Floats 
are not real numbers!

py> a = 0.01
py> b = 1e5
py> a + b - b 
0.00999999999476131
py> a + b - b == a
False


-- 
Steven



More information about the Python-list mailing list