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