Robert Smallshire <r...@sixty-north.com> added the comment: To respond to Raymond's points:
1) Nobody is suggesting that every float method should also be available on int. Clearly some methods on float are not applicable to int. 2) Taken narrowly, you're right that is_integer() does nothing useful for int. Neither do imag, denominator, __floor__, or __trunc__. They're all present so we can successfully use integers in duck-typing situations along with the other number types. My claim is that int.is_integer() is useful for the same reasons. The problem isn't that you or I don't know that we should write a == int(a) to be portable, the problem is that code that *already* uses x.is_integer() fails hard when x happens to be an int. As I've demonstrated, some built-in operators and functions can return either int or float, even when the operand types are all int, depending only on the *values* of the operands. This wouldn't matter if nobody ever wrote f.is_integer(), and instead used the trivially portable solution, but they do, and at your behest: In 2011 you published "f.is_integer() is the new way to test whether a float is integral. The old way, x==int(x), is history." The reality is that folks often write Python functions which accept *numbers*, without giving too much thought to whether calling my_func(42.0) will work, but my_func(42) will cause an unhandled exception that nobody is expecting. Indeed, one of the joys of Python is that we often don't need to overthink this. The trivial portable solution is also nearly three times slower than float.is_integer() and int.is_integer(). Moreso if you package it up in a function so it can be applied to more complex expressions in, say, a comprehension, where an intermediate assignment is not possible. I'm not the only person to be thrown by this. See this: is_integer() not working: https://stackoverflow.com/ questions/17170226/is-integer-not-working/17170511 and this: https://www.reddit.com/r/learnpython/comments/4tp4hy/ need_help_with_identify_number_as_integer/ and this https://wiesmann.codiferes.net/wordpress/?p=13366 Furthermore, once the is_integer() method is discovered, it leads to folks writing odd code in order to leverage it, such as always converting user integer input to float in order to check that it's really is an integer (which of course subtly limits the precision of allowable integers). There's an example of this on page 14 of the book *Doing Math With Python*. https://www.amazon.com/Doing-Math-Python-Programming-Statistics/dp/1593276400 Other prolific and widely respected Python programmers have described this behaviour as "kind of nuts" (though I'm not going to involve them here). The behaviour has also invited unfortunate comparisons with similar non-obvious behaviour in Javascript. 3) I'd be very surprised if the presence of this method on int caused any more confusion, or impediment to learning than do the presence of int.imag or int.denominator. 4) I'm less bothered about the numeric tower aspect than I am about duck-type compatibility between the built-in types int and float. That said, a key part of what I think is your concern about creating work for subclass implementers can be addressed by providing a default implementation Real.is_integer() in terms of int(x) == x. 5) The decimal spec doesn't require an is_decimal function, but it doesn't forbid it either. In any case, the Decimal implementation already implements is_integer internally as `cpx_mpd_isinteger` – and uses it a great deal, which demonstrates its utility. My patch simply exposes it to Python. There's no danger of violating any specification, unless that specification says that you must not implement a method called is_integer, which it doesn't, especially as we would be using a definition which is already de facto compatible with the standard. I don't care very much about Decimal either for my own work, especially as it already stands apart from the numeric tower. I implemented it to be consistent with my argument about duck typed numbers (which still largely holds for Decimal, except for floor division and modulus I believe). Solutions for which use `a == int(a)` or `a == a.to_integral_value()` fail for NaN and infinities, whereas float.is_integer() is more robust. It turns out the trivial portable solution isn't so trivial, or so portable, if implemented robustly, performantly and with duck-typing in mind. Ultimately, my argument is one about duck typing across numbers types. If if that abstraction isn't valued, I have nowhere to go. *Robert Smallshire | *Managing Director *Sixty North* | Applications | Consulting | Training r...@sixty-north.com | T +47 63 01 04 44 | M +47 924 30 350 http://sixty-north.com On 11 March 2018 at 05:58, Raymond Hettinger <rep...@bugs.python.org> wrote: > > Raymond Hettinger <raymond.hettin...@gmail.com> added the comment: > > Sorry Robert, but I object to this going forward. > > 1) We do not and should not require that every float() method also be in > int(): > > >>> set(dir(float)) - set(dir(int)) > {'fromhex', 'hex', 'is_integer', '__getformat__', '__setformat__', > 'as_integer_ratio'} > > 2) Your use case is trivially solved in a portable, trivial, and readable > way: > > a == int(a) > > 3) I really don't want to clutter the other types with this method when it > does nothing useful for those types. In particular, I expect that the > presence of "is_integer()" in the int() class will likely create more > confusion than it solves (perhaps not for you, but for the vast majority of > users, none of whom have ever requested this behavior over the entire > history of the language). > > 4) Also, I don't what this to have to propagate to every project that ever > registers their custom numeric types with the numeric tower. Adding this > method to the tower is essentially making a requirement that everyone, > everywhere must add this method. That is not in the spirit of what the > ABCs are all about -- they mostly require a small and useful subset of the > behaviors of the related concrete classes (i.e. the concrete collections > all have more methods than are required by their collections.abc > counterparts). > > 5) Lastly, the spirit of the decimal module was to stick as closely as > possible to the decimal specification and assiduously avoid extending the > spec with new inventions (risking duplication of functionality, risking > non-portability with other implementations, risking not handling special > values in a way that is consistent with the spec, risking our going down a > path that intentionally not chosen by the spec creators, or risking being > at odds with subsequent updates to the spec). > > ---------- > > _______________________________________ > Python tracker <rep...@bugs.python.org> > <https://bugs.python.org/issue26680> > _______________________________________ > ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue26680> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com