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