On Wed, Mar 21, 2018 at 10:31:19AM +0000, Chris Barker wrote: > On Wed, Mar 21, 2018 at 4:42 AM Steven D'Aprano <st...@pearwood.info> wrote: > > > Could float et al. add an __index__ method that would return a ValueError > > > if the value was not an integer? > > > > That would allow us to write things like: > > > > "abcdefgh"[5.0] > > > > which is one of the things __index__ was invented to prevent. > > I’m not so sure — it was invented to prevent using e.g. 6.1 as an index, > which int(I) would allow.
As would int(6.0). If we wanted 6.0 to be accepted as an index, then floats would already have an __index__ method :-) [...] > But Guidos point is well taken — Having __index__ fail based on value is > setting people up for bugs down the line. > > However, it seems use of is_integer() on a float is setting people up for > exactly the same sorts of bugs. I don't think so. You aren't going to stop people from testing whether a float is an integer. (And why should you? It isn't *wrong* to do so. Some floats simply are integer valued.) All you will do is force them to write code which is even worse than what they have now. One wrong solution: int(x) == x That can raise ValueError and OverflowError, but at least it is somewhat understandable. Serhiy suggested that people should use the cryptic: (not x % 1.0) but that's hardly self-documenting: its not obvious what it does or how it works. Suppose I see that snippet in a code review, and let's suppose I recognise it and aren't totally perplexed by it. Will it pass the review? I have to make a decision: - will it fail when x is an INF or NAN? - does it give the correct results when x is negative? - does this suffer from rounding errors that could affect the result? - what if x is not a float, but a Decimal, a Fraction or an int too big to convert to a float? None of the answers are obvious at a glance. In fact, Serhiy's suggestion is not correct when x is not a float: py> from fractions import Fraction py> x =Fraction(1) + Fraction(1, 10**500) # certainly not an integer py> x.denominator == 1 # sadly Fraction doesn't support is_integer False py> not x % 1.0 True > Another example is that pow() functions sometimes swap to an exact > > algorithm if the power is an int. There's no particular reason why > > x**n and x**n.0 ought to be different, but they are: > > > > py> 123**10 > > 792594609605189126649 > > > > py> 123**10.0 > > 7.925946096051892e+20 > > > I think this is exactly like the __index__ use case. If the exponent is a > literal, use what you mean. Naturally. I already eluded to that in my earlier post. Nevertheless, this is just an example, and we shouldn't expect that the power will be a literal. I'm just illustrating the concept. > If the exponent is a computed float, then you > really don’t want a different result depending on whether the computed > value is exactly an integer or one ULP off. I don't think you actually mean to say that. I'm pretty sure that we *do* want different results if the exponent differs from an integer by one ULP. After all, that's what happens now: py> x = 25 py> x**1.0 25.0 py> x**(1.0+(2**-52)) # one ULP above 25.000000000000018 py> x**(1.0-(2**-53)) # one ULP below 24.99999999999999 I don't want to change the behaviour of pow(), but we shouldn't dismiss the possibility of some other numeric function wanting to treat values N.0 and N the same. Let's say, an is_prime(x) function that supports floats as well as ints: is_prime(3.0) # True is_prime(3.00001) # False If the argument x.is_integer() returns True, then we convert to an int and test for primality. If not, then it's definitely not prime. > The user should check/convert to an integer with a method appropriate to > the problem at hand. Oh, you mean something like x.is_integer()? I agree! *wink* > If it wasn’t too heavyweight, it might be nice to have some sort of flag on > floats indicating whether they really ARE an integer, rather than happen to > be: > > -Created from an integer literal > - created from an integer object > - result of floor(), ceil() or round() I don't understand this. You seem to be saying that none of the following are "really" integer valued: float(10) floor(10.1) ceil(10.1) round(10.1) If they're not all exactly equal to the integer 10, what on earth should they equal? -- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com