Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-27 Thread Robert Smallshire
In the PR I've submitted, that's essentially what I'm doing for the default
Real.is_integer() implementation. The details differ slightly, in that I
rely on the int() constructor to call __trunc__(), rather than introduce a
new dependency on the math module.

On Tue, 27 Mar 2018 at 21:29, Chris Barker  wrote:

> I know this is all done, but for completeness’ sake:
>
> I just noticed math.trunc() and __trunc__().
>
> So wouldn’t the “correct” way to check for an integral value be something
> like:
>
> obj.__trunc__() == obj
>
> I don’t think this has any bearing on adding is_integer() methods to
> numeric objects, but might if we wanted to add a generic is_integer()
> function somewhere.
>
> In any case, I don’t recall it being mentioned in the conversation, so
> thought I’d complete the record.
>
> -CHB
>
>
>
>
>
> On Wed, Mar 21, 2018 at 8:31 PM Guido van Rossum  wrote:
>
>> On Wed, Mar 21, 2018 at 6:48 PM, Chris Barker 
>> wrote:
>>
>>> On Wed, Mar 21, 2018 at 4:12 PM, Guido van Rossum 
>>> wrote:
>>>
 Thank you! As you may or may not have noticed in a different thread,
 we're going through a small existential crisis regarding the usefulness of
 is_integer() -- Serhiy believes it is not useful (and even an attractive
 nuisance) and should be deprecated. OTOH the existence of
 dec_mpd_isinteger() seems to validate to me that it actually exposes useful
 functionality (and every Python feature can be abused, so that alone should
 not

>>> )
>>
> ___
> 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/rob%40sixty-north.com
>
-- 
*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
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-27 Thread Chris Barker
I know this is all done, but for completeness’ sake:

I just noticed math.trunc() and __trunc__().

So wouldn’t the “correct” way to check for an integral value be something
like:

obj.__trunc__() == obj

I don’t think this has any bearing on adding is_integer() methods to
numeric objects, but might if we wanted to add a generic is_integer()
function somewhere.

In any case, I don’t recall it being mentioned in the conversation, so
thought I’d complete the record.

-CHB





On Wed, Mar 21, 2018 at 8:31 PM Guido van Rossum  wrote:

> On Wed, Mar 21, 2018 at 6:48 PM, Chris Barker 
> wrote:
>
>> On Wed, Mar 21, 2018 at 4:12 PM, Guido van Rossum 
>> wrote:
>>
>>> Thank you! As you may or may not have noticed in a different thread,
>>> we're going through a small existential crisis regarding the usefulness of
>>> is_integer() -- Serhiy believes it is not useful (and even an attractive
>>> nuisance) and should be deprecated. OTOH the existence of
>>> dec_mpd_isinteger() seems to validate to me that it actually exposes useful
>>> functionality (and every Python feature can be abused, so that alone should
>>> not
>>>
>> )
>
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Guido van Rossum
On Wed, Mar 21, 2018 at 6:48 PM, Chris Barker  wrote:

> On Wed, Mar 21, 2018 at 4:12 PM, Guido van Rossum 
> wrote:
>
>> Thank you! As you may or may not have noticed in a different thread,
>> we're going through a small existential crisis regarding the usefulness of
>> is_integer() -- Serhiy believes it is not useful (and even an attractive
>> nuisance) and should be deprecated. OTOH the existence of
>> dec_mpd_isinteger() seems to validate to me that it actually exposes useful
>> functionality (and every Python feature can be abused, so that alone should
>> not be a strong argument for deprecation).
>>
>
> if not deprecated, then do we add it to all the other numeric types? Which
> was the original suggestion, yes?
>

Yes. That's a pronouncement, so we can end this thread (and more
importantly the other).

-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Chris Barker
On Wed, Mar 21, 2018 at 4:12 PM, Guido van Rossum  wrote:

> Thank you! As you may or may not have noticed in a different thread, we're
> going through a small existential crisis regarding the usefulness of
> is_integer() -- Serhiy believes it is not useful (and even an attractive
> nuisance) and should be deprecated. OTOH the existence of
> dec_mpd_isinteger() seems to validate to me that it actually exposes useful
> functionality (and every Python feature can be abused, so that alone should
> not be a strong argument for deprecation).
>

if not deprecated, then do we add it to all the other numeric types? Which
was the original suggestion, yes?

-CHB




-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Chris Barker
On Wed, Mar 21, 2018 at 12:38 PM, Steven D'Aprano 
wrote:

> In fact, Serhiy's suggestion is not correct when x is not a float:
>

This is a key point -- see some of Tim's posts -- like ot or not, you
probably need to know when you are working with a float and when you aren't
-- and what the implications of that are.

I think the key pint is this:

where does the logic of whether a given object represents an integer
belong? At first glance, it clearly belongs with the type -- floats know
how they are represented, as do fractions and decimals -- they can
determine it in an efficient and clearly defined way.

However, my argument is that while an integer-valued float is clearly
defined in the binary representation, what "is this an integer?" means is
actually use-case dependent, and thus the user should be deciding how to do
it (i.e. with isclose() or int(x) == x or 

> 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.


yes -- poorly worded -- I mean you want the slightly different result, not
a different type and algorithm - i.e continuity if you had a range of
slightly less than an integer to slightly more than an integer.

> 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*
>

That's the point -- is_integer may or may not be appropriate, and whether
it is is a function of use-case, not type.

> 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.
>

poorly worked again -- I shoud not write these on a phone


> 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)
>

I meant those are the ones that ARE really integer valued.

turns out that py3 returns an actual int for all of those other than
float() (of course) anyway, so that's pretty much been done -- and no need
for is_integer()

well, it's been fun, but looks like it's sticking around.


-CHB



-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Steven D'Aprano
On Wed, Mar 21, 2018 at 09:46:06AM -0700, Nathaniel Smith wrote:
[...]
> For me this is an argument against is_integer() rather than for it :-).
> is_prime(float) should *obviously*[1] be a TypeError. Primality is only
> meaningfully defined over the domain of integers

And 3.0 is an integer. Just because it is float *object* does not mean 
it is not an integer *value*. Do not mistake the leaky abstraction of 
multiple numeric types for the mathematical number three.

Primality-related functions are not limited to integers. For example, 
the prime counting function is defined on the reals:

https://en.wikipedia.org/wiki/Prime-counting_function

and there's no reason not to extend the domain of is_prime to any real. 
"Practicality beats purity" -- why should the result be different just 
because the input has a ".0" at the end?

Mathematically it doesn't: the answer to something like "Is 3.0 a 
prime?" is a clear Yes, not "I'm sorry, I don't understand the 
question!" which an exception would imply.

As programmers, there is always a tension between the leaky abstraction 
of our numeric types, and the mathematical equality of:

3 == 3.0 == 9/3 == 3+0j

etc. The decision on whether to be more or less restrictive on the 
*types* a function accepts is up to the individual developer. Having 
decided to be *less* restrictive, an is_integer method would be useful.

For what it's worth, Wolfram|Alpha gives inconsistant results. It allows 
testing of rationals for primality:

"Is 9/3 a prime?"

evaluates as true, but:

"Is 3.0 a prime?"

gets parsed as "Is 3 a prime number?" and yet evaluates as false. A 
clear bug for software using a natural-language interface and intended 
to be used by students and non-mathematicans.


> and this is a case where
> operator.index is exactly what you want.

It is exactly not what I want. 


> Of course it's just an example, and perhaps there are other, better
> examples. But it makes me nervous that this is the best example you could
> quickly come up with.

I actually had to work hard to come up with an example as simple and 
understandable as primality testing. The first example I thought of was 
Bessel functions of the 1st and 2nd kind with arbitrary real-valued 
orders, where you *absolutely* do want order 3.0 (float) and order 3 
(int) to be precisely the same.

But I avoided giving it because I thought it would be too technical and 
it would intimidate people. I thought that the prime number example 
would be easier to understand.

Next time I want to make a point, I'll go for argument by intimidation.

*wink*


-- 
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Nathaniel Smith
On Mar 21, 2018 05:40, "Steven D'Aprano"  wrote:


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.1)  # False


For me this is an argument against is_integer() rather than for it :-).
is_prime(float) should *obviously*[1] be a TypeError. Primality is only
meaningfully defined over the domain of integers, and this is a case where
operator.index is exactly what you want.

Of course it's just an example, and perhaps there are other, better
examples. But it makes me nervous that this is the best example you could
quickly come up with.

-n

[1] Warning: I am not Dutch.
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Guido van Rossum
Thank you! As you may or may not have noticed in a different thread, we're
going through a small existential crisis regarding the usefulness of
is_integer() -- Serhiy believes it is not useful (and even an attractive
nuisance) and should be deprecated. OTOH the existence of
dec_mpd_isinteger() seems to validate to me that it actually exposes useful
functionality (and every Python feature can be abused, so that alone should
not be a strong argument for deprecation).

On Wed, Mar 21, 2018 at 1:33 AM, Robert Smallshire 
wrote:

> As requested on the bug tracker, I've submitted a pull request for
> is_integer() support on the other numeric types.
> https://github.com/python/cpython/pull/6121
>
> These are the tactics I used to implement it:
>
> - float: is_integer() already exists, so no changes
>
> - int:  return True
>
> - Real: return x == int(x). Although Real doesn't explicitly support
> conversation to int with __int__, it does support conversion to int with
> __trunc__. The int constructor falls back to using __trunc__.
>
> - Rational (also inherited by Fraction): return x.denominator == 1 as
> Rational requires that all numbers must be represented in lowest form.
>
> - Integral: return True
>
> - Decimal: expose the existing dec_mpd_isinteger C function to Python as
> is_integer()
>
>
> ___
> 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/
> guido%40python.org
>
>


-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Robert Smallshire
As requested on the bug tracker, I've submitted a pull request for
is_integer() support on the other numeric types.
https://github.com/python/cpython/pull/6121

These are the tactics I used to implement it:

- float: is_integer() already exists, so no changes

- int:  return True

- Real: return x == int(x). Although Real doesn't explicitly support
conversation to int with __int__, it does support conversion to int with
__trunc__. The int constructor falls back to using __trunc__.

- Rational (also inherited by Fraction): return x.denominator == 1 as
Rational requires that all numbers must be represented in lowest form.

- Integral: return True

- Decimal: expose the existing dec_mpd_isinteger C function to Python as
is_integer()
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Steven D'Aprano
On Wed, Mar 21, 2018 at 10:31:19AM +, Chris Barker wrote:
> On Wed, Mar 21, 2018 at 4:42 AM Steven D'Aprano  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.018
py> x**(1.0-(2**-53))  # one ULP below
24.99


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.1)  # 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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Nick Coghlan
On 14 March 2018 at 08:29, Tim Peters  wrote:

> [Tim]
> >> An obvious way to extend it is for Fraction() to look for a special
> >> method too, say "_as_integer_ratio()".
>
> [Greg Ewing]
> > Why not __as_integer_ratio__?
>
> Because. at this point, that would be beating a dead horse ;-)
>

I'm not so sure about that, as if we define a protocol method for it, then
we'd presumably also define an "operator.as_integer_ratio" function, and
that function could check __index__ in addition to checking the new
protocol method.

For example:

def as_integer_ratio(n):
# Automatically accept true integers
if hasattr(n, "__index__"):
return (n.__index__(), 1)
# New reserved protocol method
if hasattr(n, "__integer_ratio__"):
return n.__integer_ratio__()
# Historical public protocol method
if hasattr(n, "as_integer_ratio"):
return n.as_integer_ratio()
# Check for lossless integer conversion
try:
int_n = int(n)
except TypeError:
pass
else:
if int_n == n:
return (int_n, 1)
raise TypeError(f"{type(n)} does not support conversion to an
integer ratio")

Similarly, on the "operator.is_integer" front:

def is_integer(n):
# Automatically accept true integers
if hasattr(n, "__index__"):
return True
# New reserved protocol method
if hasattr(n, "__is_integer__"):
return n.__is_integer__()
# Historical public protocol method
if hasattr(n, "is_integer"):
return n.is_integer()
# As a last resort, check for lossless int conversion
return int(n) == n

Cheers,
Nick.

P.S. I've suggested "operator" as a possible location, since that's where
we put "operator.index", and it's a low level module that doesn't bring in
any transitive dependencies. However, putting these protocol wrappers
somewhere else (e.g. in "math" or "numbers") may also make sense.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-21 Thread Chris Barker
On Wed, Mar 21, 2018 at 4:42 AM Steven D'Aprano  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.

More specifically, it was invented to Allow true integers that aren’t a
python int ( like numpy int types).

But, in fact, it is common to use floating point computation to compute an
index — though usually one would make a conscious choice between round()
and floor() and ceil() when doing so.

Passing floor(a_float) as an index is a perfectly reasonable thing to do.

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.

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. 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.

The user should check/convert to an integer with a method appropriate to
the problem at hand.

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()

Any others?

But that would be too heavyweight, and not that useful.

In short, is_integer() is an attractive nuisance.

-CHB

PS: for the power example, the “right” solution is to have two operators:
integer power and float power, like we do for float vs floor division. No,
it’s not worth it in this case, but having it be value dependent would be
worse than type dependent.







>
> On the other hand, some might argue that by passing 10.0 as the power, I
> am specifically requesting a float implementation and result. I don't
> wish to argue in favour of either position, but just to point out that
> it is sometimes reasonable to want to know whether a float represents an
> exact integer value or not.
>
>
>
> --
> 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/chris.barker%40noaa.gov
>
-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-20 Thread Steven D'Aprano
On Wed, Mar 21, 2018 at 12:32:11AM +, Chris Barker 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.


> Of course, as pointed out earlier in this thread, an "exact" integer is
> probably not what you want with a float anyway

Not always. For example, I might want a function factorial(x) which 
returns x! when x is an exact integer value, and gamma(x+1) when it is 
not. That is what the HP-48 series of calculators do.

(This is just an illustration.)

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


On the other hand, some might argue that by passing 10.0 as the power, I 
am specifically requesting a float implementation and result. I don't 
wish to argue in favour of either position, but just to point out that 
it is sometimes reasonable to want to know whether a float represents an 
exact integer value or not.



-- 
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-20 Thread Guido van Rossum
No, the whole point of __index__ is that it refuses *all* floats --
otherwise people will do approximate computations that for their simple
test inputs give whole numbers, use them as sequence indices, and then find
their code broken only when the computation incurs some floating point
approximation. OTOH, is_integer() specifically asks whether a given real
value is a whole number so you can cast it to int() without rounding, etc.

On Tue, Mar 20, 2018 at 5:32 PM, Chris Barker  wrote:

> It seems .as_integer_ratio() has been resolved.
>
> what about the original .is_integer() request? (Or did I miss that
> somehow?)
>
> Anyway, it seems like __index__() should play a role here somehow... isn't
> that how you ask an object for the integer version of itself?
>
> Could float et al. add an __index__ method that would return a ValueError
> if the value was not an integer?
>
> Of course, as pointed out earlier in this thread, an "exact" integer is
> probably not what you want with a float anyway
>
> -CHB
>
>
> On Tue, Mar 13, 2018 at 10:29 PM, Tim Peters  wrote:
>
>> [Tim]
>> >> An obvious way to extend it is for Fraction() to look for a special
>> >> method too, say "_as_integer_ratio()".
>>
>> [Greg Ewing]
>> > Why not __as_integer_ratio__?
>>
>> Because. at this point, that would be beating a dead horse ;-)
>> ___
>> 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/chris.
>> barker%40noaa.gov
>>
>
>
>
> --
>
> Christopher Barker, Ph.D.
> Oceanographer
>
> Emergency Response Division
> NOAA/NOS/OR(206) 526-6959   voice
> 7600 Sand Point Way NE   (206) 526-6329   fax
> Seattle, WA  98115   (206) 526-6317   main reception
>
> chris.bar...@noaa.gov
>
> ___
> 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/
> guido%40python.org
>
>


-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-20 Thread Chris Barker
It seems .as_integer_ratio() has been resolved.

what about the original .is_integer() request? (Or did I miss that somehow?)

Anyway, it seems like __index__() should play a role here somehow... isn't
that how you ask an object for the integer version of itself?

Could float et al. add an __index__ method that would return a ValueError
if the value was not an integer?

Of course, as pointed out earlier in this thread, an "exact" integer is
probably not what you want with a float anyway

-CHB


On Tue, Mar 13, 2018 at 10:29 PM, Tim Peters  wrote:

> [Tim]
> >> An obvious way to extend it is for Fraction() to look for a special
> >> method too, say "_as_integer_ratio()".
>
> [Greg Ewing]
> > Why not __as_integer_ratio__?
>
> Because. at this point, that would be beating a dead horse ;-)
> ___
> 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/
> chris.barker%40noaa.gov
>



-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Tim Peters
[Tim]
>> An obvious way to extend it is for Fraction() to look for a special
>> method too, say "_as_integer_ratio()".

[Greg Ewing]
> Why not __as_integer_ratio__?

Because. at this point, that would be beating a dead horse ;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Greg Ewing

Tim Peters wrote:

An obvious way to extend it is for Fraction() to look for a special
method too, say "_as_integer_ratio()".


Why not __as_integer_ratio__?

--
Greg

___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Raymond Hettinger

> On Mar 13, 2018, at 12:07 PM, Guido van Rossum  wrote:
> 
> OK, please make it so.

Will do.  I'll create a tracker issue right away.

Since this one looks easy (as many things do at first), I would like to assign 
it to Nofar Schnider (one of my mentees).


Raymond



> 
> On Tue, Mar 13, 2018 at 11:39 AM, Raymond Hettinger 
>  wrote:
> 
> 
> > On Mar 13, 2018, at 10:43 AM, Guido van Rossum  wrote:
> >
> > So let's make as_integer_ratio() the standard protocol for "how to make a 
> > Fraction out of a number that doesn't implement numbers.Rational". We 
> > already have two examples of this (float and Decimal) and perhaps numpy or 
> > the sometimes proposed fixed-width decimal type can benefit from it too. If 
> > this means we should add it to int, that's fine with me.
> 
> I would like that outcome.
> 
> The signature x.as_integer_ratio() -> (int, int) is pleasant to work with.  
> The output is easy to explain, and the denominator isn't tied to powers of 
> two or ten. Since Python ints are exact and unbounded, there isn't worry 
> about range or rounding issues.
> 
> In contrast, math.frexp(float) ->(float, int) is a bit of pain because it 
> still leaves you in the domain of floats rather than letting you decompose to 
> more more basic types.  It's nice to have a way to move down the chain from 
> ℚ, ℝ, or ℂ to the more basic ℤ (of course, that only works because floats and 
> complex are implemented in a way that precludes exact irrationals).
> 
> 
> Raymond
> 
> 
> 
> 
> 
> -- 
> --Guido van Rossum (python.org/~guido)

___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Guido van Rossum
OK, please make it so.

On Tue, Mar 13, 2018 at 11:39 AM, Raymond Hettinger <
raymond.hettin...@gmail.com> wrote:

>
>
> > On Mar 13, 2018, at 10:43 AM, Guido van Rossum  wrote:
> >
> > So let's make as_integer_ratio() the standard protocol for "how to make
> a Fraction out of a number that doesn't implement numbers.Rational". We
> already have two examples of this (float and Decimal) and perhaps numpy or
> the sometimes proposed fixed-width decimal type can benefit from it too. If
> this means we should add it to int, that's fine with me.
>
> I would like that outcome.
>
> The signature x.as_integer_ratio() -> (int, int) is pleasant to work
> with.  The output is easy to explain, and the denominator isn't tied to
> powers of two or ten. Since Python ints are exact and unbounded, there
> isn't worry about range or rounding issues.
>
> In contrast, math.frexp(float) ->(float, int) is a bit of pain because it
> still leaves you in the domain of floats rather than letting you decompose
> to more more basic types.  It's nice to have a way to move down the chain
> from ℚ, ℝ, or ℂ to the more basic ℤ (of course, that only works because
> floats and complex are implemented in a way that precludes exact
> irrationals).
>
>
> Raymond
>
>
>


-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Raymond Hettinger


> On Mar 13, 2018, at 10:43 AM, Guido van Rossum  wrote:
> 
> So let's make as_integer_ratio() the standard protocol for "how to make a 
> Fraction out of a number that doesn't implement numbers.Rational". We already 
> have two examples of this (float and Decimal) and perhaps numpy or the 
> sometimes proposed fixed-width decimal type can benefit from it too. If this 
> means we should add it to int, that's fine with me.

I would like that outcome.  

The signature x.as_integer_ratio() -> (int, int) is pleasant to work with.  The 
output is easy to explain, and the denominator isn't tied to powers of two or 
ten. Since Python ints are exact and unbounded, there isn't worry about range 
or rounding issues.

In contrast, math.frexp(float) ->(float, int) is a bit of pain because it still 
leaves you in the domain of floats rather than letting you decompose to more 
more basic types.  It's nice to have a way to move down the chain from ℚ, ℝ, or 
ℂ to the more basic ℤ (of course, that only works because floats and complex 
are implemented in a way that precludes exact irrationals).


Raymond


___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Tim Peters
[Guido]
> So let's make as_integer_ratio() the standard protocol for "how to make a
> Fraction out of a number that doesn't implement numbers.Rational". We
> already have two examples of this (float and Decimal) and perhaps numpy or
> the sometimes proposed fixed-width decimal type can benefit from it too.

Yup, that works.  I only would have preferred that you went back in
time to add a leading underscore.


> If this means we should add it to int, that's fine with me.

Given that int.numerator and int.denominator already exist, there's no
plausible "good reason" to refuse to return them as twople.  Still,
I'd wait for someone to complain ;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Guido van Rossum
So let's make as_integer_ratio() the standard protocol for "how to make a
Fraction out of a number that doesn't implement numbers.Rational". We
already have two examples of this (float and Decimal) and perhaps numpy or
the sometimes proposed fixed-width decimal type can benefit from it too. If
this means we should add it to int, that's fine with me.

On Tue, Mar 13, 2018 at 9:37 AM, Tim Peters  wrote:

> [Tim]
> >> At heart, the Fraction() constructor is _all about_ creating integer
> >> ratios, so is the most natural place to put knowledge of how to do so.
> >> A protocol for allowing new numeric types to get converted to Fraction
> >> would be more generally useful than just a weird method only datetime
> >> uses ;-)
>
> [Guido]
> > Ironically, the various Fraction constructors *calls* as_integer_ratio()
> for
> > floats and Decimals. From which follows IMO that the float and Decimal
> > classes are the right place to encapsulate the knowledge on how to do it.
>
> It appears that as_integer_ratio was slammed into floats and Decimals
> precisely _so that_ Fraction() could call them, while Fraction has its
> own self-contained knowledge of how to convert ints and Fractions and
> strings and numbers.Rationals to Fraction (and the former types don't
> support as_integer_ratio).
>
> That's fine, but my objection is subtler:  the actual answer to "can
> this thing be converted to an integer ratio?" is not "does it support
> as_integer_ratio?",  but rather "can Fraction() deal with it?" - and
> there's currently no way for a new numeric type to say "and here's how
> I can be converted to Fraction".
>
> An obvious way to extend it is for Fraction() to look for a special
> method too, say "_as_integer_ratio()".  The leading underscore would
> reflect the truth:  that this wasn't really intended to be a public
> method on its own, but is an internal protocol for use by the
> Fraction() constructor.
>
> Then it would be obvious that, e.g., it would be just plain stupid ;-)
> for `int` to bother implementing _as_integer_ratio.  The only real
> point of the method is to play nice with the Fraction constructor.
> _As is_, it's jarring that int.as_integer_ratio() doesn't exist - for
> the same reason it's jarring int.hex() doesn't exist.
>
> If Mark or I wanted to use float._as_integer_ratio() directly too,
> that's fine: we're numeric grownups and won't throw a hissy fit if
> ints don't support it too ;-)
>



-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Tim Peters
[Tim]
>> At heart, the Fraction() constructor is _all about_ creating integer
>> ratios, so is the most natural place to put knowledge of how to do so.
>> A protocol for allowing new numeric types to get converted to Fraction
>> would be more generally useful than just a weird method only datetime
>> uses ;-)

[Guido]
> Ironically, the various Fraction constructors *calls* as_integer_ratio() for
> floats and Decimals. From which follows IMO that the float and Decimal
> classes are the right place to encapsulate the knowledge on how to do it.

It appears that as_integer_ratio was slammed into floats and Decimals
precisely _so that_ Fraction() could call them, while Fraction has its
own self-contained knowledge of how to convert ints and Fractions and
strings and numbers.Rationals to Fraction (and the former types don't
support as_integer_ratio).

That's fine, but my objection is subtler:  the actual answer to "can
this thing be converted to an integer ratio?" is not "does it support
as_integer_ratio?",  but rather "can Fraction() deal with it?" - and
there's currently no way for a new numeric type to say "and here's how
I can be converted to Fraction".

An obvious way to extend it is for Fraction() to look for a special
method too, say "_as_integer_ratio()".  The leading underscore would
reflect the truth:  that this wasn't really intended to be a public
method on its own, but is an internal protocol for use by the
Fraction() constructor.

Then it would be obvious that, e.g., it would be just plain stupid ;-)
for `int` to bother implementing _as_integer_ratio.  The only real
point of the method is to play nice with the Fraction constructor.
_As is_, it's jarring that int.as_integer_ratio() doesn't exist - for
the same reason it's jarring int.hex() doesn't exist.

If Mark or I wanted to use float._as_integer_ratio() directly too,
that's fine: we're numeric grownups and won't throw a hissy fit if
ints don't support it too ;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Guido van Rossum
On Mon, Mar 12, 2018 at 10:01 PM, Tim Peters  wrote:

> At heart, the Fraction() constructor is _all about_ creating integer
> ratios, so is the most natural place to put knowledge of how to do so.
> A protocol for allowing new numeric types to get converted to Fraction
> would be more generally useful than just a weird method only datetime
> uses ;-)
>

Ironically, the various Fraction constructors *calls* as_integer_ratio()
for floats and Decimals. From which follows IMO that the float and Decimal
classes are the right place to encapsulate the knowledge on how to do it.

-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Steven D'Aprano
On Mon, Mar 12, 2018 at 09:49:27AM -0700, Raymond Hettinger wrote:

> * We already have a simple, traditional, portable, and readable way to 
> make the test: int(x) == x


Alas, the simple way is not always the correct way:

py> x = float('inf')
py> x == int(x)
Traceback (most recent call last):
  File "", line 1, in 
OverflowError: cannot convert float infinity to integer

So to be correct, you need to catch OverflowError, ValueError (in case 
of NANs), and TypeError (in case of complex numbers).

Or guard against them with isinstance() and math.isfinite() tests. But 
doing so has its own problems:

py> x = Decimal('snan')
py> math.isfinite(x)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: cannot convert signaling NaN to float


> * In the context of ints, the test x.is_integer() always returns True.  
> This isn't very useful.

It is if you don't know what type x is ahead of time.

if x.is_integer():

versus:

if isinstance(x, int) or isinstance(x, float) and x.is_integer()


> Does it cost us anything?
> * Yes, adding a method to the numeric tower makes it a requirement for 
> every class that ever has or ever will register or inherit from the 
> tower ABCs.

Could the numeric tower offer a default implementation that should work 
for most numeric types? The default could possibly even be 

int(self) == self

Then you only have to implement your own if you have special cases to 
consider, like floats, or can optimise the test. Many numbers ought to 
know if they are integer valued, without bothering to do a full 
conversion to int. For example, Fractions could return 

self.denominator == 1

as a cheap test for integerness.


> * Adding methods to a core object such as int() increases the 
> cognitive load for everyday users who look at dir(), call help(), or 
> read the main docs.

This is a good point, but not an overwhelming one.


> What does "API Parsimony" mean?
> * Avoidance of feature creep.
> * Preference for only one obvious way to do things.
> * Practicality (not craving things you don't really need) beats purity 
> (symmetry and foolish consistency).
> * YAGNI suggests holding off in the absence of clear need.
> * Recognition that smaller APIs are generally better for users.

A very nice list! Thank you for that!

But the last one is true only to a point. It is possible to be too 
small. (The Python 1.5 API is *much* smaller than Python 3.6. I don't 
think that it was better.) And consider that a *consistent* API is often 
more important than a *minimalist* API.



-- 
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Mark Dickinson
On Mon, Mar 12, 2018 at 9:18 PM, Tim Peters  wrote:

> [Guido]
> >  as_integer_ratio() seems mostly cute (it has Tim Peters all
> > over it),
>
> Nope!  I had nothing to do with it.  I would have been -0.5 on adding
> it had I been aware at the time.
>

Looks like it snuck into the float type as part of the fractions.Fraction
work in https://bugs.python.org/issue1682 . I couldn't find much related
discussion; I suspect that the move was primarily for optimization (see
https://github.com/python/cpython/commit/3ea7b41b5805c60a05e697211d0bfc14a62a19fb).
Decimal.as_integer_ratio was added here: https://bugs.python.org/issue25928
 .

I do have significant uses of `float.as_integer_ratio` in my own code, and
wouldn't enjoy seeing it being deprecated/ripped out, though I guess I'd
cope.

Some on this thread have suggested that things like is_integer and
as_integer_ratio should be math module functions. Any suggestions for how
that might be made to work? Would we special-case the types we know about,
and handle only those (so the math module would end up having to know about
the fractions and decimal modules)? Or add a new magic method (e.g.,
__as_integer_ratio__) for each case we want to handle, like we do for
math.__floor__, math.__trunc__ and math.__ceil__? Or use some form of
single dispatch, so that custom types can register their own handlers? The
majority of current math module functions simply convert their arguments to
a float, so a naive implementation of math.is_integer in the same style
wouldn't work: it would give incorrect results for a non-integral Decimal
instance that ended up getting rounded to an integral value by the float
conversion.

Mark
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Serhiy Storchaka

13.03.18 10:35, Larry Hastings пише:

On 03/12/2018 08:41 PM, Guido van Rossum wrote:
If you force me to choose between allowing hex(3.14) or 42.hex() I'll 
choose the latter


I assume you meant (42).hex() here.  If you're also interested in 
changing the language to permit 42.hex(), well, color me shocked :D


(For those who haven't seen this before: it's a well-known gotcha. When 
Python's grammar sees "42.hex()", it thinks "42." is the start of a 
floating-point constant.  But "42.hex" isn't a valid floating-point 
constant, so it throws a SyntaxError.)


"42." is a valid floating-point constant. But a floating-point constant 
followed by an identifier is an invalid syntax. This is the same error 
as in "42. hex" and "42 hex".


___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-13 Thread Larry Hastings



On 03/12/2018 08:41 PM, Guido van Rossum wrote:
If you force me to choose between allowing hex(3.14) or 42.hex() I'll 
choose the latter


I assume you meant (42).hex() here.  If you're also interested in 
changing the language to permit 42.hex(), well, color me shocked :D


(For those who haven't seen this before: it's a well-known gotcha. When 
Python's grammar sees "42.hex()", it thinks "42." is the start of a 
floating-point constant.  But "42.hex" isn't a valid floating-point 
constant, so it throws a SyntaxError.)



//arry/
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Tim Peters
[Tim. on as_integer_ratio()]
>> - I expect the audience is tiny.

[Alexander Belopolsky]
> The datetime module would benefit from having as_integer_ratio()
> supported by more types.  It's been hard to resist requests to allow
> Decimal in timedelta constructors and/or arithmetics

I don't see the connection.  That timedelta construction may use
as_integer_ratio() today doesn't mean it _has_ to use
as_integer_ratio() forever, and is no reason (to my mind) to add
as_integer_ratio all over the place.

Why not drop that, and in oddball cases see whether
fractions.Fraction() can handle the input?

>>> fractions.Fraction(decimal.Decimal("1.76"))
Fraction(44, 25)

Probably less efficient, but I don't care ;-)  And then, e.g.,
timedelta would also automagically allow Fraction arguments (which,
BTW, don't support as_integer_ratio() either).  Bonus:  if datetime is
bothering with hand-coding rational arithmetic now out of concern to
get every bit right, Fraction could handle that too by itself.

At heart, the Fraction() constructor is _all about_ creating integer
ratios, so is the most natural place to put knowledge of how to do so.
A protocol for allowing new numeric types to get converted to Fraction
would be more generally useful than just a weird method only datetime
uses ;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Tim Peters
[Tim Peters]
>> ...
>> >>> (-math.inf) ** 3.1
>> inf

[David Mertz]
> Weird. I take it that's what IEEE-754 says. NaN would sure be more intuitive
> here since inf+inf-j is not in the domain of Reals. Well, technically
> neither is inf, but at least it's the limit of the domain. :-).

Mathematical reals have all sorts of properties floats fail to
capture, while mathematical reals don't distinguish between -0 and +0
at all.  "Practical' symmetry arguments often underlie what float
standards require.  At heart , the rules for infinite arguments are
often _consequences_ of "more obvious" rules for signed zero
arguments, following from replacing +-inf with 1/+-0 in the latter.

More explanation here:

https://stackoverflow.com/questions/10367011/why-is-pow-infinity-positive-non-integer-infinity

But we're not required to _like_ it; we just have to implement it ;-)


>> >>> (-math.inf) ** 3.0 # NOTE THIS ONE
>> -inf
>> >>> (-math.inf) ** 2.9
>> inf
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread David Mertz
On Mon, Mar 12, 2018, 3:25 PM Tim Peters  wrote:

> [David Mertz ]
> > ...
> > I can see no sane reason why anyone would ever call float.is_integer()
> > actually. That should always be spelled math.isclose(x, int(x)) because
> > IEEE-754. Attractive nuisance is probably too generous, I'd simply call
> the
> > method a bug.
>
> Sometimes it's necessary to know, and especially when _implementing_
> 754-conforming functions.  For example, what negative infinity raised
> to a power needs to return depends on whether the power is an integer
> (specifically on whether it's an odd integer):
>
> >>> (-math.inf) ** 3.1
> inf
>

Weird. I take it that's what IEEE-754 says. NaN would sure be more
intuitive here since inf+inf-j is not in the domain of Reals. Well,
technically neither is inf, but at least it's the limit of the domain. :-).

>>> (-math.inf) ** 3.0 # NOTE THIS ONE
> -inf
> >>> (-math.inf) ** 2.9
> inf
>
> But, ya, for most people most of the time I agree is_integer() is an
> attractive nuisance.  People implementing math functions are famous
> for cheerfully enduring any amount of pain needed to get the job done
> ;-)
>
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Tim Peters
[David Mertz ]
> ...
> I can see no sane reason why anyone would ever call float.is_integer()
> actually. That should always be spelled math.isclose(x, int(x)) because
> IEEE-754. Attractive nuisance is probably too generous, I'd simply call the
> method a bug.

Sometimes it's necessary to know, and especially when _implementing_
754-conforming functions.  For example, what negative infinity raised
to a power needs to return depends on whether the power is an integer
(specifically on whether it's an odd integer):

>>> (-math.inf) ** random.random()
inf
>>> (-math.inf) ** random.random()
inf
>>> (-math.inf) ** random.random()
inf
>>> (-math.inf) ** 3.1
inf
>>> (-math.inf) ** 3.0 # NOTE THIS ONE
-inf
>>> (-math.inf) ** 2.9
inf

But, ya, for most people most of the time I agree is_integer() is an
attractive nuisance.  People implementing math functions are famous
for cheerfully enduring any amount of pain needed to get the job done
;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Alexander Belopolsky
On Mon, Mar 12, 2018 at 5:18 PM, Tim Peters  wrote:
> [Guido]
>>  as_integer_ratio() seems mostly cute (it has Tim Peters all
>> over it),
>
> Nope!  I had nothing to do with it.  I would have been -0.5 on adding
> it had I been aware at the time.
>
> - I expect the audience is tiny.

The datetime module would benefit from having as_integer_ratio()
supported by more types.  It's been hard to resist requests to allow
Decimal in timedelta constructors and/or arithmetics

>>> timedelta(Decimal('1.5'))
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported type for timedelta days component: decimal.Decimal

but

>>> timedelta(1.5)
datetime.timedelta(days=1, seconds=43200)

I don't recall why we decided not to accept anything with an
.as_integer_ratio() method.

See  for additional discussion.
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread David Mertz
If anyone cares, my vote is to rip out both .as_integer_ratio() and
.is_integer() from Python. I've never used either and wouldn't want to.

Both seem like perfectly good functions for the `math` module, albeit the
former is simply the Fraction() constructor.

I can see no sane reason why anyone would ever call float.is_integer()
actually. That should always be spelled math.isclose(x, int(x)) because
IEEE-754. Attractive nuisance is probably too generous, I'd simply call the
method a bug.

On Mon, Mar 12, 2018, 2:21 PM Tim Peters  wrote:

> [Guido]
> >  as_integer_ratio() seems mostly cute (it has Tim Peters all
> > over it),
>
> Nope!  I had nothing to do with it.  I would have been -0.5 on adding
> it had I been aware at the time.
>
> - I expect the audience is tiny.
>
> - While, ya, _I_ have uses for it, I had a utility function for it
> approximately forever (it's easily built on top of math.frexp()).
>
> - Especially now, fractions.Fraction(some_float) is the same thing
> except for return type.
>
>
> > OTOH it looks like Decimal has it,
>
> Looks like ints got it first, and then spread to Decimal because "why
> not?" ;-)  The first attempt to spread it to Decimal I found was
> rejected (which would have been my vote too):
>
> https://bugs.python.org/issue8947
>
>
> > so I think this ship has sailed too and maybe it's best to add it to the
> > numeric tower just to be done with it.
>
> Or rip it out of everything.  Either way works for me ;-)
> ___
> 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/mertz%40gnosis.cx
>
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Tim Peters
[Guido]
>  as_integer_ratio() seems mostly cute (it has Tim Peters all
> over it),

Nope!  I had nothing to do with it.  I would have been -0.5 on adding
it had I been aware at the time.

- I expect the audience is tiny.

- While, ya, _I_ have uses for it, I had a utility function for it
approximately forever (it's easily built on top of math.frexp()).

- Especially now, fractions.Fraction(some_float) is the same thing
except for return type.


> OTOH it looks like Decimal has it,

Looks like ints got it first, and then spread to Decimal because "why
not?" ;-)  The first attempt to spread it to Decimal I found was
rejected (which would have been my vote too):

https://bugs.python.org/issue8947


> so I think this ship has sailed too and maybe it's best to add it to the
> numeric tower just to be done with it.

Or rip it out of everything.  Either way works for me ;-)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Guido van Rossum
On Mon, Mar 12, 2018 at 1:03 PM, Raymond Hettinger <
raymond.hettin...@gmail.com> wrote:

>
> > On Mar 12, 2018, at 12:15 PM, Guido van Rossum  wrote:
> >
> > There's a reason why adding this to int feels right to me. In mypy we
> treat int as a sub*type* of float, even though technically it isn't a
> sub*class*. The absence of an is_integer() method on int means that this
> code has a bug that mypy doesn't catch:
> >
> > def f(x: float):
> > if x.is_integer():
> > "do something"
> > else:
> > "do something else"
> >
> > f(12)
>
> Do you have any thoughts about the other non-corresponding float methods?
>

Not really, but I'll try below.


> >>> set(dir(float)) - set(dir(int))
>{'as_integer_ratio', 'hex', '__getformat__', 'is_integer',
> '__setformat__', 'fromhex'}
>

IIUC fromhex is a class method so the story isn't the same there -- typical
use is float.fromhex(). as_integer_ratio() seems mostly cute (it has Tim
Peters all over it), OTOH it looks like Decimal has it, so I think this
ship has sailed too and maybe it's best to add it to the numeric tower just
to be done with it.

I found a comment for __getformat__ saying "You probably don't want to use
this function. It exists mainly to be used in Python's test suite" so let's
skip that.

So that leaves hex(). There I think it's preposterous that for ints you
have to write hex(i) but for floats you must write x.hex(). The idea that
the user always knows whether they have an int or a float is outdated (it
stems back to the very early Python days when 3.14 + 42 was a type error --
Tim talked me out of that in '91 or '92). If you force me to choose between
allowing hex(3.14) or 42.hex() I'll choose the latter -- we also have
bytes.hex() and it's an easier change to add a hex() method to int than to
extend the hex() function -- we'd have to add a __hex__ protocol first.


> In general, would you prefer that functionality like is_integer() be a
> math module function or that is should be a method on all numeric types
> except Complex?  I expect questions like this to recur over time.
>

That feels like a loaded question -- we have a math module because C has
one and back in 1990 I didn't want to spend time thinking about such design
issues.


> Also, do you have any thoughts on the feature itself?  Serhiy ran a Github
> search and found that it was baiting people into worrisome code like:
> (x/5).is_integer() or (x**0.5).is_integer()
>

Finding bad example of floating point use is like stealing candy from
babies. The feature seems venerable so I think there would have to be a
very high bar to deprecate it -- I don't think you want to go there.


> > So I think the OP of the bug has a valid point, 27 years without this
> feature notwithstanding.
>
> Okay, I'll ask the OP to update his patch :-)
>

-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Raymond Hettinger

> On Mar 12, 2018, at 12:15 PM, Guido van Rossum  wrote:
> 
> There's a reason why adding this to int feels right to me. In mypy we treat 
> int as a sub*type* of float, even though technically it isn't a sub*class*. 
> The absence of an is_integer() method on int means that this code has a bug 
> that mypy doesn't catch:
> 
> def f(x: float):
> if x.is_integer():
> "do something"
> else:
> "do something else"
> 
> f(12)

Do you have any thoughts about the other non-corresponding float methods?

>>> set(dir(float)) - set(dir(int))
   {'as_integer_ratio', 'hex', '__getformat__', 'is_integer', '__setformat__', 
'fromhex'}

In general, would you prefer that functionality like is_integer() be a math 
module function or that is should be a method on all numeric types except 
Complex?  I expect questions like this to recur over time.

Also, do you have any thoughts on the feature itself?  Serhiy ran a Github 
search and found that it was baiting people into worrisome code like:  
(x/5).is_integer() or (x**0.5).is_integer()

> So I think the OP of the bug has a valid point, 27 years without this feature 
> notwithstanding.

Okay, I'll ask the OP to update his patch :-)


Raymond
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Serhiy Storchaka

12.03.18 21:15, Guido van Rossum пише:
There's a reason why adding this to int feels right to me. In mypy we 
treat int as a sub*type* of float, even though technically it isn't a 
sub*class*.. The absence of an is_integer() method on int means that 
this code has a bug that mypy doesn't catch:


def f(x: float):
     if x.is_integer():
     "do something"
     else:
     "do something else"


What is the real use case of float.is_integer()?

I searched on GitHub and found only misuses of it like 
(x/5).is_integer() (x % 5 == 0 would be more correct and clear) or 
(x**0.5).is_integer() (returns wrong result for large ints and some 
floats) in short examples. Some of these snippets look like book 
examples, and they propagate bad practices (like "if a.is_integer() == 
True:").


___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Guido van Rossum
There's a reason why adding this to int feels right to me. In mypy we treat
int as a sub*type* of float, even though technically it isn't a sub*class*.
The absence of an is_integer() method on int means that this code has a bug
that mypy doesn't catch:

def f(x: float):
if x.is_integer():
"do something"
else:
"do something else"

f(12)

This passes the type check (because 12 is considered an acceptable
substitute for float) but currently fails at runtime (because x is an int
and does not have that method).

You may think that mypy is obviously wrong here, but in fact we (the Python
community) have gone through considerable hoops to make other cases like
this work at runtime (e.g. adding .imag and .real to int), and disallowing
ints where a float is expected in mypy would cause unacceptable noise about
many valid programs (the difference in runtime behavior between int and
float was much more pronounced in Python 2, where integer division
truncated, and we intentionally changed that for the same reason).

So I think the OP of the bug has a valid point, 27 years without this
feature notwithstanding.

And while mypy does not endorse or use the numeric tower, given the strong
argument for adding the method to int, it makes sense to add it to all
types in the numeric tower as well. I have no strong opinion about what to
do for Decimal, which in general doesn't like to play nice with other ABCs
(in general I think Decimal is doing itself a disfavor by favoring the
language-independent Decimal standard over Python conventions, but that's a
discussion for another time).


On Mon, Mar 12, 2018 at 11:10 AM, Antoine Pitrou 
wrote:

> On Mon, 12 Mar 2018 09:49:27 -0700
> Raymond Hettinger  wrote:
> >
> > Starting point: Do we need this?
> > * We already have a simple, traditional, portable, and readable way to
> make the test:  int(x) == x
>
> It doesn't look that obvious to me.  As a reviewer I would request to
> add a comment explaining the test.
>
> > * Aside from the OP, this behavior has never been requested in Python's
> 27 year history.
>
> That's possible.  One thing I often see is suboptimal compatibility
> with third-party integer types such as Numpy ints, but that's a
> slightly different request (as it usually doesn't imply accepting
> Numpy floats that exactly represent integrals).
>
> > Does it cost us anything?
> > * Yes, adding a method to the numeric tower makes it a requirement for
> every class that ever has or ever will register or inherit from the tower
> ABCs.
>
> Well, the big question is whether the notion of numeric tower is useful
> in Python at all.  If it's useful then there's a point to expand its
> usability with such a feature.  Personally I don't care much :-)
>
> > As a result, we ended-up with an awkward and error-prone API that
> requires double parenthesis for the valid use case:  url.endswith(('.html',
> '.css')).
>
> It doesn't look that awkward to me.
>
> Regards
>
> Antoine.
>
>
>
>
> ___
> 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/
> guido%40python.org
>



-- 
--Guido van Rossum (python.org/~guido)
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Mark Dickinson
On Mon, Mar 12, 2018 at 4:49 PM, Raymond Hettinger <
raymond.hettin...@gmail.com> wrote:

> What is the proposal?
> * Add an is_integer() method to int(), Decimal(), Fraction(), and Real().
> Modify Rational() to provide a default implementation.
>

>From the issue discussion, it sounds to me as though the OP would be
content with adding is_integer to int and Fraction (leaving the decimal
module and the numeric tower alone).


> Starting point: Do we need this?
> * We already have a simple, traditional, portable, and readable way to
> make the test:  int(x) == x
>

As already pointed out in the issue discussion, this solution isn't
particularly portable (it'll fail for infinities and nans), and can be
horribly inefficient in the case of a Decimal input with large exponent:

In [1]: import decimal
In [2]: x = decimal.Decimal('1e9')
In [3]: %timeit x == int(x)
1.42 s ± 6.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [4]: %timeit x == x.to_integral_value()
230 ns ± 2.03 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

* In the context of ints, the test x.is_integer() always returns True.
> This isn't very useful.
>

It's useful in the context of duck typing, which I believe is a large part
of the OP's point. For a value x that's known to be *either* float or int
(which is not an uncommon situation), it makes x.is_integer() valid without
needing to know the specific type of x.

* It conflicts with a design goal for the decimal module to not invent new
> functionality beyond the spec unless essential for integration with the
> rest of the language.  The reasons included portability with other
> implementations and not trying to guess what the committee would have
> decided in the face of tricky questions such as whether
> Decimal('1.01').is_integer()
> should return True when the context precision is only three decimal places
> (i.e. whether context precision and rounding traps should be applied before
> the test and whether context flags should change after the test).
>

I don't believe there's any ambiguity here. The correct behaviour looks
clear: the context isn't used, no flags are touched, and the method returns
True if and only if the value is finite and an exact integer. This is
analogous to the existing is-sNaN, is-signed, is-finite, is-zero,
is-infinite tests, none of which are affected by (or affect) context.

-- 
Mark
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Antoine Pitrou
On Mon, 12 Mar 2018 09:49:27 -0700
Raymond Hettinger  wrote:
> 
> Starting point: Do we need this?
> * We already have a simple, traditional, portable, and readable way to make 
> the test:  int(x) == x

It doesn't look that obvious to me.  As a reviewer I would request to
add a comment explaining the test.

> * Aside from the OP, this behavior has never been requested in Python's 27 
> year history.

That's possible.  One thing I often see is suboptimal compatibility
with third-party integer types such as Numpy ints, but that's a
slightly different request (as it usually doesn't imply accepting
Numpy floats that exactly represent integrals).

> Does it cost us anything?
> * Yes, adding a method to the numeric tower makes it a requirement for every 
> class that ever has or ever will register or inherit from the tower ABCs.

Well, the big question is whether the notion of numeric tower is useful
in Python at all.  If it's useful then there's a point to expand its
usability with such a feature.  Personally I don't care much :-)

> As a result, we ended-up with an awkward and error-prone API that requires 
> double parenthesis for the valid use case:  url.endswith(('.html', '.css')).

It doesn't look that awkward to me.

Regards

Antoine.




___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Paul Moore
On 12 March 2018 at 17:59, Serhiy Storchaka  wrote:
> 12.03.18 18:49, Raymond Hettinger пише:
>>
>> There is a feature request and patch to propagate the float.is_integer()
>> API through rest of the numeric types ( https://bugs.python.org/issue26680
>> ).
>>
>> While I don't think it is a good idea, the OP has been persistent and
>> wants his patch to go forward.
>>
>> It may be worthwhile to discuss on this list to help resolve this
>> particular request and to address the more general, recurring design
>> questions. Once a feature with a marginally valid use case is added to an
>> API, it is common for us to get downstream requests to propagate that API to
>> other places where it makes less sense but does restore a sense of symmetry
>> or consistency.  In cases where an abstract base class is involved,
>> acceptance of the request is usually automatic (i.e. range() and tuple()
>> objects growing index() and count() methods).  However, when our hand hasn't
>> been forced, there is still an opportunity to decline.  That said,
>> proponents of symmetry requests tend to feel strongly about it and tend to
>> never fully accept such a request being declined (it leaves them with a
>> sense
>>   that Python is disordered and unbalanced).
>>
>>
>> Raymond
>>
>>
>>  My thoughts on the feature request -
>
>
> I concur with Raymond at all points about this concrete feature and about
> the general design in general.

So do I.

I do think that there is an element of considered judgement in all of
these types of request, and it's right that each such request be
considered on its merits. But I do not think that "symmetry with other
cases" is a merit in itself, it needs to be subjected to precisely the
same sort of scrutiny as any other argument.

In this case, Raymond's arguments seem persuasive to me (in
particular, the uselessness of int.is_integer() and the complexities
in deciding correct behaviour for Decimal.is_integer() in the absence
of an answer in the standard). I would ask why a standalone
is_integer() function, targeted at somewhere in the stdlib like the
math module[1] isn't acceptable, and I'd be wanting to see use cases
for the functionality - in particular use cases for a generic "can be
used for an unknown type" solution, as opposed to type-specific
solutions like float.is_integer or (Fraction.denominator == 1). I
imagine these questions have already been thrashed out on the tracker,
though.

It's certainly true that people get particularly wedded to
symmetry/consistency arguments. Sometimes such arguments have value
(discoverability, teachability, ease of writing type-agnostic code)
but we should keep that value in perspective.

Paul

[1] with possibly a period for development as a 3rd party library,
although I can see that "being built in" may be a key benefit of a
proposal like this
___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Serhiy Storchaka

12.03.18 18:49, Raymond Hettinger пише:

There is a feature request and patch to propagate the float.is_integer() API 
through rest of the numeric types ( https://bugs.python.org/issue26680 ).

While I don't think it is a good idea, the OP has been persistent and wants his 
patch to go forward.

It may be worthwhile to discuss on this list to help resolve this particular 
request and to address the more general, recurring design questions. Once a 
feature with a marginally valid use case is added to an API, it is common for 
us to get downstream requests to propagate that API to other places where it 
makes less sense but does restore a sense of symmetry or consistency.  In cases 
where an abstract base class is involved, acceptance of the request is usually 
automatic (i.e. range() and tuple() objects growing index() and count() 
methods).  However, when our hand hasn't been forced, there is still an 
opportunity to decline.  That said, proponents of symmetry requests tend to 
feel strongly about it and tend to never fully accept such a request being 
declined (it leaves them with a sense
  that Python is disordered and unbalanced).


Raymond


 My thoughts on the feature request -


I concur with Raymond at all points about this concrete feature and 
about the general design in general.


___
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


Re: [Python-Dev] Symmetry arguments for API expansion

2018-03-12 Thread Gregory P. Smith
On Mon, Mar 12, 2018 at 9:51 AM Raymond Hettinger <
raymond.hettin...@gmail.com> wrote:

> There is a feature request and patch to propagate the float.is_integer()
> API through rest of the numeric types ( https://bugs.python.org/issue26680
> ).
>
> While I don't think it is a good idea, the OP has been persistent and
> wants his patch to go forward.
>
> It may be worthwhile to discuss on this list to help resolve this
> particular request and to address the more general, recurring design
> questions. Once a feature with a marginally valid use case is added to an
> API, it is common for us to get downstream requests to propagate that API
> to other places where it makes less sense but does restore a sense of
> symmetry or consistency.  In cases where an abstract base class is
> involved, acceptance of the request is usually automatic (i.e. range() and
> tuple() objects growing index() and count() methods).  However, when our
> hand hasn't been forced, there is still an opportunity to decline.  That
> said, proponents of symmetry requests tend to feel strongly about it and
> tend to never fully accept such a request being declined (it leaves them
> with a sense that Python is disordered and unbalanced).
>
>
> Raymond
>
>
>  My thoughts on the feature request -
>
> What is the proposal?
> * Add an is_integer() method to int(), Decimal(), Fraction(), and Real().
> Modify Rational() to provide a default implementation.
>
> Starting point: Do we need this?
> * We already have a simple, traditional, portable, and readable way to
> make the test:  int(x) == x
>

Mark Dickerson left a comment on the bug pointing out that such a test is
not great as it can lead to an excessive amount of computation to create
the int from some numeric types such as Decimal when all that is desired is
something the type itself may be able to answer without that.


> * In the context of ints, the test x.is_integer() always returns True.
> This isn't very useful.
> * Aside from the OP, this behavior has never been requested in Python's 27
> year history.
>
> Does it cost us anything?
> * Yes, adding a method to the numeric tower makes it a requirement for
> every class that ever has or ever will register or inherit from the tower
> ABCs.
> * Adding methods to a core object such as int() increases the cognitive
> load for everyday users who look at dir(), call help(), or read the main
> docs.
> * It conflicts with a design goal for the decimal module to not invent new
> functionality beyond the spec unless essential for integration with the
> rest of the language.  The reasons included portability with other
> implementations and not trying to guess what the committee would have
> decided in the face of tricky questions such as whether
> Decimal('1.01').is_integer()
> should return True when the context precision is only three decimal places
> (i.e. whether context precision and rounding traps should be applied before
> the test and whether context flags should change after the test).
>
> Shouldn't everything in a concrete class also be in an ABC and all its
> subclasses?
> * In general, the answer is no.  The ABCs are intended to span only basic
> functionality.  For example, GvR intentionally omitted update() from the
> Set() ABC because the need was fulfilled by __ior__().
>
> But int() already has real, imag, numerator, and denominator, why is this
> different?
> * Those attributes are central to the functioning of the numeric tower.
> * In contrast, the is_integer() method is a peripheral and incidental
> concept.
>
> What does "API Parsimony" mean?
> * Avoidance of feature creep.
> * Preference for only one obvious way to do things.
> * Practicality (not craving things you don't really need) beats purity
> (symmetry and foolish consistency).
> * YAGNI suggests holding off in the absence of clear need.
> * Recognition that smaller APIs are generally better for users.
>
> Are there problems with symmetry/consistency arguments?
> * The need for guard rails on an overpass doesn't imply the same need on a
> underpass even though both are in the category of grade changing byways.
> * "In for a penny, in for a pound" isn't a principle of good design;
> rather, it is a slippery slope whereby the acceptance of a questionable
> feature in one place seems to compel later decisions to propagate the
> feature to other places where the cost / benefit trade-offs are less
> favorable.
>
> Should float.as_integer() have ever been added in the first place?
> * Likely, it should have been a math module function like isclose() and
> isinf() so that it would not have been type specific.
> * However, that ship has sailed; instead, the question is whether we now
> have to double down and have to dispatch other ships as well.
> * There is some question as to whether it is even a good idea to be
> testing the results of floating point calculations for exact values. It may
> be useful for testing inputs, but is likely a trap for people using