Considering that Fraction and Decimal did not exist yet, what type do
you think the PEP 238 implementers should have chosen for the result
of dividing two ints? If float is not acceptable, and int is not
acceptable (which was the whole point of the PEP), then the only
alternative I can see would have been to raise a TypeError and force
the user to upcast explicitly. In that case, dividing arbitrary ints
using floating-point math would not be possible for those ints that
are outside the range of floats; you would get OverflowError on the
upcast operation, regardless of whether the result of division would
be within the range of a float.
More importantly, it's useful for implementers of generic mathematical
routines. If you're passed arbitrary inputs, you don't have to check
the types of the values you were given and then branch if both of the
values you were about to divide happened to be ints just because the
division operator arbitrarily does something different on ints.
Or you just cast one of them to float. That way you're sure you're
working with floats.
The main trouble is that float is not a perfect superset of int. If it
were, then it really would be upcasting, same as turning a float into
a complex is; there's no downside, other than performance.
If I'd been in charge, I would have simply let int/int continue to
return an int, as that's the one thing that is guaranteed not to
behave differently on different input values. Python 3 fixed Unicode
handling by ensuring that mixing text and bytes would cause problems
straight away, rather than waiting until you get a character with a
codepoint higher than U+00FF; 3.3 went further and made sure you
wouldn't get problems by going past U+FFFF even on Windows. I think we
all agree (well, all bar the trolls) that that was a good thing. So
why do we have this sort of thing go weird?
def always_true(x):
assert type(x) is int
return x*10/2 == x*5
In Python 2, I believe that will indeed be always true, for any
integer x. (Yeah, there's a naughty type check in there. I'm talking
about integers, mmkay?) In Python 3, it might not be.
False
(32-bit Windows, because I'm on the laptop. Other Pythons, other CPUs,
etc, may have different points where that happens, but the same will
happen.)
So either you keep a very close eye on everything to make sure you
don't have floats infecting your calculations, or you ignore the
problem and then start seeing odd stuff happen with specific numbers.
I'd rather have to explicitly request floating-point division; that
way, you get issues a lot sooner and more simply. "Why is 34/10 equal
to 3?" is a lot easier to explain than "Why does my program not work
when I give it numbers with lots of data encoded in them, when it
works fine with sequential numbers from zero?". (Imagine if you work
with invoice numbers, for instance, and your code is fine; but if you
encode the date into the first eight digits, then put the store number
in the next three, register number in the next three, and then the
last three are sequential. Should work the same, right?)
Anyway, way too late to change now. That ship sailed in 2.2 or thereabouts.
ChrisA