[Python-checkins] bpo-33073: Adding as_integer_ratio to ints. (GH-8750)

Raymond Hettinger webhook-mailer at python.org
Fri Sep 14 02:56:27 EDT 2018


https://github.com/python/cpython/commit/5ac704306f4b81ae3f28d8742408d3214b145e8a
commit: 5ac704306f4b81ae3f28d8742408d3214b145e8a
branch: master
author: Lisa Roach <lisaroach14 at gmail.com>
committer: Raymond Hettinger <rhettinger at users.noreply.github.com>
date: 2018-09-13T23:56:23-07:00
summary:

bpo-33073: Adding as_integer_ratio to ints. (GH-8750)

files:
A Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst
M Doc/library/stdtypes.rst
M Doc/whatsnew/3.8.rst
M Lib/test/test_doctest.py
M Lib/test/test_long.py
M Misc/ACKS
M Objects/clinic/longobject.c.h
M Objects/longobject.c

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index fd59a5170dae..5a133e32fced 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -537,6 +537,14 @@ class`. In addition, it provides a few more methods:
 
     .. versionadded:: 3.2
 
+.. method:: int.as_integer_ratio()
+
+   Return a pair of integers whose ratio is exactly equal to the original
+   integer and with a positive denominator. The integer ratio of integers
+   (whole numbers) is always the integer as the numerator and ``1`` as the
+   denominator.
+
+   .. versionadded:: 3.8
 
 Additional Methods on Float
 ---------------------------
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index b2475c7df33e..38b8623dddd2 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -91,6 +91,10 @@ Other Language Changes
   was lifted.
   (Contributed by Serhiy Storchaka in :issue:`32489`.)
 
+* The ``int`` type now has a new ``as_integer_ratio`` method compatible
+  with the existing ``float.as_integer_ratio`` method.
+  (Contributed by Lisa Roach in :issue:`33073`.)
+
 * Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
   (Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
 
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 83941c129f44..797bdb847190 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -665,7 +665,7 @@ def non_Python_modules(): r"""
     True
     >>> real_tests = [t for t in tests if len(t.examples) > 0]
     >>> len(real_tests) # objects that actually have doctests
-    8
+    9
     >>> for t in real_tests:
     ...     print('{}  {}'.format(len(t.examples), t.name))
     ...
@@ -675,6 +675,7 @@ def non_Python_modules(): r"""
     2  builtins.float.hex
     1  builtins.hex
     1  builtins.int
+    3  builtins.int.as_integer_ratio
     2  builtins.int.bit_length
     1  builtins.oct
 
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 8472889d48ba..7c883baebb41 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -3,6 +3,7 @@
 
 import sys
 
+import enum
 import random
 import math
 import array
@@ -1349,6 +1350,37 @@ def test_shift_bool(self):
                 self.assertEqual(type(value << shift), int)
                 self.assertEqual(type(value >> shift), int)
 
+    def test_as_integer_ratio(self):
+        tests = [10, 0, -10, 1]
+        for value in tests:
+            numerator, denominator = value.as_integer_ratio()
+            self.assertEqual((numerator, denominator), (value, 1))
+            self.assertIsInstance(numerator, int)
+            self.assertIsInstance(denominator, int)
+
+    def test_as_integer_ratio_maxint(self):
+        x = sys.maxsize + 1
+        self.assertEqual(x.as_integer_ratio()[0], x)
+
+    def test_as_integer_ratio_bool(self):
+        self.assertEqual(True.as_integer_ratio(), (1, 1))
+        self.assertEqual(False.as_integer_ratio(), (0, 1))
+        self.assertEqual(type(True.as_integer_ratio()[0]), int)
+        self.assertEqual(type(False.as_integer_ratio()[0]), int)
+
+    def test_as_integer_ratio_int_enum(self):
+        class Foo(enum.IntEnum):
+            X = 42
+        self.assertEqual(Foo.X.as_integer_ratio(), (42, 1))
+        self.assertEqual(type(Foo.X.as_integer_ratio()[0]), int)
+
+    def test_as_integer_ratio_int_flag(self):
+        class Foo(enum.IntFlag):
+            R = 1 << 2
+        self.assertEqual(Foo.R.as_integer_ratio(), (4, 1))
+        self.assertEqual(type(Foo.R.as_integer_ratio()[0]), int)
+
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/ACKS b/Misc/ACKS
index 96985358e236..a29ff6020bbf 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1350,6 +1350,7 @@ Juan M. Bello Rivas
 Mohd Sanad Zaki Rizvi
 Davide Rizzo
 Anthony Roach
+Lisa Roach
 Carl Robben
 Ben Roberts
 Mark Roberts
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst b/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst
new file mode 100644
index 000000000000..ce9b6129f96e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst	
@@ -0,0 +1 @@
+Added as_integer_ratio to ints to make them more interoperable with floats.
diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h
index 14f5515c7a62..0e70fe5d8c44 100644
--- a/Objects/clinic/longobject.c.h
+++ b/Objects/clinic/longobject.c.h
@@ -118,6 +118,34 @@ int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored))
     return int_bit_length_impl(self);
 }
 
+PyDoc_STRVAR(int_as_integer_ratio__doc__,
+"as_integer_ratio($self, /)\n"
+"--\n"
+"\n"
+"Return integer ratio.\n"
+"\n"
+"Return a pair of integers, whose ratio is exactly equal to the original int\n"
+"and with a positive denominator.\n"
+"\n"
+">>> (10).as_integer_ratio()\n"
+"(10, 1)\n"
+">>> (-10).as_integer_ratio()\n"
+"(-10, 1)\n"
+">>> (0).as_integer_ratio()\n"
+"(0, 1)");
+
+#define INT_AS_INTEGER_RATIO_METHODDEF    \
+    {"as_integer_ratio", (PyCFunction)int_as_integer_ratio, METH_NOARGS, int_as_integer_ratio__doc__},
+
+static PyObject *
+int_as_integer_ratio_impl(PyObject *self);
+
+static PyObject *
+int_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    return int_as_integer_ratio_impl(self);
+}
+
 PyDoc_STRVAR(int_to_bytes__doc__,
 "to_bytes($self, /, length, byteorder, *, signed=False)\n"
 "--\n"
@@ -211,4 +239,4 @@ int_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyOb
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=fd64beb83bd16df3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6d5e92d7dc803751 input=a9049054013a1b77]*/
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 399d35427099..98ff9a8c265b 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -5260,6 +5260,36 @@ long_is_finite(PyObject *v)
 }
 #endif
 
+/*[clinic input]
+int.as_integer_ratio
+
+Return integer ratio.
+
+Return a pair of integers, whose ratio is exactly equal to the original int
+and with a positive denominator.
+
+>>> (10).as_integer_ratio()
+(10, 1)
+>>> (-10).as_integer_ratio()
+(-10, 1)
+>>> (0).as_integer_ratio()
+(0, 1)
+[clinic start generated code]*/
+
+static PyObject *
+int_as_integer_ratio_impl(PyObject *self)
+/*[clinic end generated code: output=e60803ae1cc8621a input=55ce3058e15de393]*/
+{
+    if PyLong_CheckExact(self) {
+        return PyTuple_Pack(2, self, _PyLong_One);
+    } else {
+        PyObject *numerator = _PyLong_Copy(self);
+        PyObject *ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One);
+        Py_DECREF(numerator);
+        return ratio_tuple;
+    }
+}
+
 /*[clinic input]
 int.to_bytes
 
@@ -5392,6 +5422,7 @@ static PyMethodDef long_methods[] = {
 #endif
     INT_TO_BYTES_METHODDEF
     INT_FROM_BYTES_METHODDEF
+    INT_AS_INTEGER_RATIO_METHODDEF
     {"__trunc__",       long_long_meth, METH_NOARGS,
      "Truncating an Integral returns itself."},
     {"__floor__",       long_long_meth, METH_NOARGS,



More information about the Python-checkins mailing list