]> granicus.if.org Git - python/commitdiff
bpo-33073: Adding as_integer_ratio to ints. (GH-8750)
authorLisa Roach <lisaroach14@gmail.com>
Fri, 14 Sep 2018 06:56:23 +0000 (23:56 -0700)
committerRaymond Hettinger <rhettinger@users.noreply.github.com>
Fri, 14 Sep 2018 06:56:23 +0000 (23:56 -0700)
Doc/library/stdtypes.rst
Doc/whatsnew/3.8.rst
Lib/test/test_doctest.py
Lib/test/test_long.py
Misc/ACKS
Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst [new file with mode: 0644]
Objects/clinic/longobject.c.h
Objects/longobject.c

index fd59a5170daedc8ae15ed2c8638ea86b72aed330..5a133e32fced7e70567dcf59ae47a6b2d782cbcf 100644 (file)
@@ -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
 ---------------------------
index b2475c7df33e06761d75120da7a43ab9d55e089e..38b8623dddd241f868e6443ab709e758b2f42921 100644 (file)
@@ -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`.)
 
index 83941c129f44630e1b73df8ed5c3439d1f745252..797bdb8471904b25e5da02e3f08099ffa13530e4 100644 (file)
@@ -665,7 +665,7 @@ plain ol' Python and is guaranteed to be available.
     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 @@ plain ol' Python and is guaranteed to be available.
     2  builtins.float.hex
     1  builtins.hex
     1  builtins.int
+    3  builtins.int.as_integer_ratio
     2  builtins.int.bit_length
     1  builtins.oct
 
index 8472889d48badee25062c2e64359d967c1910f83..7c883baebb410e0ac342238e3f0fdd658147ff5a 100644 (file)
@@ -3,6 +3,7 @@ from test import support
 
 import sys
 
+import enum
 import random
 import math
 import array
@@ -1349,6 +1350,37 @@ class LongTest(unittest.TestCase):
                 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()
index 96985358e2363f840dddec1b87ff89df38fc760c..a29ff6020bbfc3977391a0def32d6cb369951c1d 100644 (file)
--- 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 (file)
index 0000000..ce9b612
--- /dev/null
@@ -0,0 +1 @@
+Added as_integer_ratio to ints to make them more interoperable with floats.
index 14f5515c7a626ec3170ada0c87beffcb7e4f732f..0e70fe5d8c44044f800416832f848405b42702b6 100644 (file)
@@ -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]*/
index 399d35427099017d25bb2bcc4d9836b10b3e4ac6..98ff9a8c265bc547ee60a748752c2d234ffc041d 100644 (file)
@@ -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,