-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
bpo-26680: Incorporate is_integer in all built-in and standard library numeric types #6121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d80b017
b46a9dc
3b1677f
f78bf5c
6a905a8
cc07ee5
3ae9866
54ca820
a9e364d
11db7f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -621,6 +621,13 @@ Decimal objects | |
Return :const:`True` if the argument is either positive or negative | ||
infinity and :const:`False` otherwise. | ||
|
||
.. method:: is_integer() | ||
|
||
Return :const:`True` if the argument is a finite integral value and | ||
:const:`False` otherwise. | ||
|
||
.. versionadded:: 3.10 | ||
|
||
.. method:: is_nan() | ||
|
||
Return :const:`True` if the argument is a (quiet or signaling) NaN and | ||
|
@@ -1215,6 +1222,13 @@ In addition to the three supplied contexts, new contexts can be created with the | |
Returns ``True`` if *x* is infinite; otherwise returns ``False``. | ||
|
||
|
||
.. method:: is_integer(x) | ||
|
||
Returns ``True`` if *x* is finite and integral; otherwise | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One day it would be nice to fix all these docstrings for consistency (both with one another and with PEP 257). But not today. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, when you hop around the code you notice how different they all are. I tried to go for local consistency rather than global consistency. |
||
returns ``False``. | ||
|
||
.. versionadded:: 3.10 | ||
|
||
.. method:: is_nan(x) | ||
|
||
Returns ``True`` if *x* is a qNaN or sNaN; otherwise returns ``False``. | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -148,7 +148,7 @@ class Real(Complex): | |||||
"""To Complex, Real adds the operations that work on real numbers. | ||||||
|
||||||
In short, those are: a conversion to float, trunc(), divmod, | ||||||
%, <, <=, >, and >=. | ||||||
is_integer, %, <, <=, >, and >=. | ||||||
|
||||||
Real also provides defaults for the derived operations. | ||||||
""" | ||||||
|
@@ -242,6 +242,17 @@ def __le__(self, other): | |||||
"""self <= other""" | ||||||
raise NotImplementedError | ||||||
|
||||||
def is_integer(self): | ||||||
"""Return True if the Real is integral; otherwise return False. | ||||||
|
||||||
This default implementation can be overridden in subclasses | ||||||
for performance reasons or to deal with values such as NaN, | ||||||
which would otherwise cause an exception to be raised. | ||||||
""" | ||||||
# Although __int__ is not defined at this level, the int | ||||||
# constructor falls back to __trunc__, which we do have. | ||||||
return self == int(self) | ||||||
|
||||||
# Concrete implementations of Complex abstract methods. | ||||||
def __complex__(self): | ||||||
"""complex(self) == complex(float(self), 0)""" | ||||||
|
@@ -290,6 +301,10 @@ def __float__(self): | |||||
""" | ||||||
return self.numerator / self.denominator | ||||||
|
||||||
def is_integer(self): | ||||||
"""Return True if the Rational is integral; otherwise return False.""" | ||||||
return self.denominator == 1 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Must There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If not,
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah. I see the doc is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that docstring could definitely be improved. Apart from that clarification, we could do with a line or two describing what the |
||||||
|
||||||
|
||||||
class Integral(Rational): | ||||||
"""Integral adds a conversion to int and the bit-string operations.""" | ||||||
|
@@ -386,4 +401,8 @@ def denominator(self): | |||||
"""Integers have a denominator of 1.""" | ||||||
return 1 | ||||||
|
||||||
def is_integer(self): | ||||||
"""Return True; all Integrals represent an integral value.""" | ||||||
return True | ||||||
|
||||||
Integral.register(int) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -276,6 +276,7 @@ def setUp(self): | |
'is_snan', | ||
'is_subnormal', | ||
'is_zero', | ||
'is_integer', | ||
'same_quantum') | ||
|
||
def read_unlimited(self, v, context): | ||
|
@@ -2726,6 +2727,7 @@ def test_named_parameters(self): | |
self.assertRaises(TypeError, D(1).is_snan, context=xc) | ||
self.assertRaises(TypeError, D(1).is_signed, context=xc) | ||
self.assertRaises(TypeError, D(1).is_zero, context=xc) | ||
self.assertRaises(TypeError, D(1).is_integer, context=xc) | ||
|
||
self.assertFalse(D("0.01").is_normal(context=xc)) | ||
self.assertTrue(D("0.01").is_subnormal(context=xc)) | ||
|
@@ -3197,6 +3199,15 @@ def test_is_zero(self): | |
self.assertEqual(c.is_zero(10), d) | ||
self.assertRaises(TypeError, c.is_zero, '10') | ||
|
||
def test_is_integer(self): | ||
Decimal = self.decimal.Decimal | ||
Context = self.decimal.Context | ||
|
||
c = Context() | ||
b = c.is_integer(Decimal(10)) | ||
self.assertEqual(c.is_integer(10), b) | ||
self.assertRaises(TypeError, c.is_integer, '10') | ||
|
||
def test_ln(self): | ||
Decimal = self.decimal.Decimal | ||
Context = self.decimal.Context | ||
|
@@ -4360,6 +4371,19 @@ def test_implicit_context(self): | |
self.assertTrue(Decimal("-1").is_signed()) | ||
self.assertTrue(Decimal("0").is_zero()) | ||
self.assertTrue(Decimal("0").is_zero()) | ||
self.assertTrue(Decimal("-1").is_integer()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be worth adding a couple of tests for cases where the exponent isn't Ideally, we'd also test that no Decimal floating-point flags are ever raised. An easy way to do this would be to add some testcases to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
self.assertTrue(Decimal("0").is_integer()) | ||
self.assertTrue(Decimal("1").is_integer()) | ||
self.assertTrue(Decimal("42").is_integer()) | ||
self.assertTrue(Decimal("1e2").is_integer()) | ||
self.assertFalse(Decimal("1.5").is_integer()) | ||
self.assertFalse(Decimal("1e-2").is_integer()) | ||
self.assertFalse(Decimal("NaN").is_integer()) | ||
self.assertFalse(Decimal("-NaN").is_integer()) | ||
self.assertFalse(Decimal("sNaN").is_integer()) | ||
self.assertFalse(Decimal("-sNaN").is_integer()) | ||
self.assertFalse(Decimal("Inf").is_integer()) | ||
self.assertFalse(Decimal("-Inf").is_integer()) | ||
|
||
# Copy | ||
with localcontext() as c: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
The int type now supports the x.is_integer() method for compatibility with | ||
float. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
The x.is_integer() method is incorporated into the abstract types of the | ||
numeric tower, Real, Rational and Integral, with appropriate default | ||
implementations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
The d.is_integer() method is added to the Decimal type, for compatibility | ||
with other number types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a
.. versionadded:: 3.10
note here and in the other relevant bits of documentation.EDIT: edited the comment to update the version; the original suggestion of 3.8 is obviously out of date
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.