GeezerVison is showing bugs.python.org — bugs.python.org
# HG changeset patch
# User Robert Smallshire
Incorporates the float.is_integer method into the numeric tower.
Adds an is_integer method to int objects for consistency with float, allowing floats and ints to share more of a common interface. Of course, the implementation for int always returns True.
Adds a test for int.is_integer method.
Real.is_integer is abstract. Rational.is_integer provides a default implementation. Integral.is_integer always returns True.
Documentation for Real.is_integer() and Rational.is_integer()
Tests for Fraction.is_integer
Relocates documentation for is_integer from float to Real
diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst
index 718a50e..4e0c507 100644
--- a/Doc/library/numbers.rst
+++ b/Doc/library/numbers.rst
@@ -49,6 +49,11 @@ The numeric tower
:func:`round`, :func:`math.floor`, :func:`math.ceil`, :func:`divmod`, ``//``,
``%``, ``<``, ``<=``, ``>``, and ``>=``.
+ .. abstractmethod:: is_integer()
+
+ Abstract. Returns :const:`True` if this number is finite and integral,
+ otherwise :const:`False`.
+
Real also provides defaults for :func:`complex`, :attr:`~Complex.real`,
:attr:`~Complex.imag`, and :meth:`~Complex.conjugate`.
@@ -68,6 +73,7 @@ The numeric tower
Abstract.
+ Rational also provides a default for :func:`~Real.is_integer`.
.. class:: Integral
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 43a3cda..ecd849b 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -374,6 +374,9 @@ the following operations:
+--------------------+------------------------------------+--------+
| ``math.ceil(x)`` | the least integral float >= *x* | |
+--------------------+------------------------------------+--------+
+| ``x.is_integer()`` | True if *x* is finite with | |
+| | integral value, otherwise False. | |
++--------------------+------------------------------------+--------+
For additional numeric operations see the :mod:`math` and :mod:`cmath`
modules.
@@ -547,16 +550,6 @@ class`. float also has the following additional methods.
:exc:`OverflowError` on infinities and a :exc:`ValueError` on
NaNs.
-.. method:: float.is_integer()
-
- Return ``True`` if the float instance is finite with integral
- value, and ``False`` otherwise::
-
- >>> (-2.0).is_integer()
- True
- >>> (3.2).is_integer()
- False
-
Two methods support conversion to
and from hexadecimal strings. Since Python's floats are stored
internally as binary numbers, converting a float to or from a
diff --git a/Lib/numbers.py b/Lib/numbers.py
index 7eedc63..5bab740 100644
--- a/Lib/numbers.py
+++ b/Lib/numbers.py
@@ -242,6 +242,11 @@ class Real(Complex):
"""self <= other"""
raise NotImplementedError
+ @abstractmethod
+ def is_integer(self):
+ """Return True if the Real is an integer."""
+ raise NotImplementedError
+
# Concrete implementations of Complex abstract methods.
def __complex__(self):
"""complex(self) == complex(float(self), 0)"""
@@ -290,6 +295,10 @@ class Rational(Real):
"""
return self.numerator / self.denominator
+ def is_integer(self):
+ """Return True if the Rational is an integer."""
+ return self.numerator % self.denominator == 0
+
class Integral(Rational):
"""Integral adds a conversion to int and the bit-string operations."""
@@ -386,4 +395,8 @@ class Integral(Rational):
"""Integers have a denominator of 1."""
return 1
+ def is_integer(self):
+ """Always returns True."""
+ return True
+
Integral.register(int)
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 73d2dd3..f571331 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -617,5 +617,15 @@ class FractionTest(unittest.TestCase):
r = F(13, 7)
self.assertRaises(AttributeError, setattr, r, 'a', 10)
+ def test_is_integer(self):
+ self.assertTrue(F(1, 1).is_integer())
+ self.assertTrue(F(2, 1).is_integer())
+ self.assertTrue(F(3, 1).is_integer())
+ self.assertTrue(F(2, 2).is_integer())
+ self.assertTrue(F(3, 3).is_integer())
+ self.assertFalse(F(1, 2).is_integer())
+ self.assertFalse(F(1, 3).is_integer())
+ self.assertFalse(F(2, 3).is_integer())
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 5b8b4dc..d1be898 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1236,6 +1236,9 @@ class LongTest(unittest.TestCase):
self.assertRaises(TypeError, myint.from_bytes, 0, 'big')
self.assertRaises(TypeError, int.from_bytes, 0, 'big', True)
+ def test_is_integer(self):
+ self.assertTrue(int(42).is_integer())
+
def test_access_to_nonexistent_digit_0(self):
# http://bugs.python.org/issue14630: A bug in _PyLong_Copy meant that
# ob_digit[0] was being incorrectly accessed for instances of a
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 70d8cfc..a5ad454 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -5241,6 +5241,12 @@ byte order of the host system, use `sys.byteorder' as the byte order value.\n\
The signed keyword-only argument indicates whether two's complement is\n\
used to represent the integer.");
+static PyObject *
+long_is_integer(PyObject *v)
+{
+ Py_RETURN_TRUE;
+}
+
static PyMethodDef long_methods[] = {
{"conjugate", (PyCFunction)long_long, METH_NOARGS,
"Returns self, the complex conjugate of any int."},
@@ -5254,6 +5260,8 @@ static PyMethodDef long_methods[] = {
METH_VARARGS|METH_KEYWORDS, long_to_bytes_doc},
{"from_bytes", (PyCFunction)long_from_bytes,
METH_VARARGS|METH_KEYWORDS|METH_CLASS, long_from_bytes_doc},
+ {"is_integer", (PyCFunction)long_is_integer, METH_NOARGS,
+ "Always True for int objects."},
{"__trunc__", (PyCFunction)long_long, METH_NOARGS,
"Truncating an Integral returns itself."},
{"__floor__", (PyCFunction)long_long, METH_NOARGS,