Commit 5ac70430 authored by Lisa Roach's avatar Lisa Roach Committed by Raymond Hettinger

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

parent 83df50ea
...@@ -537,6 +537,14 @@ class`. In addition, it provides a few more methods: ...@@ -537,6 +537,14 @@ class`. In addition, it provides a few more methods:
.. versionadded:: 3.2 .. 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 Additional Methods on Float
--------------------------- ---------------------------
......
...@@ -91,6 +91,10 @@ Other Language Changes ...@@ -91,6 +91,10 @@ Other Language Changes
was lifted. was lifted.
(Contributed by Serhiy Storchaka in :issue:`32489`.) (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>`. * Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.) (Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
......
...@@ -665,7 +665,7 @@ plain ol' Python and is guaranteed to be available. ...@@ -665,7 +665,7 @@ plain ol' Python and is guaranteed to be available.
True True
>>> real_tests = [t for t in tests if len(t.examples) > 0] >>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests >>> len(real_tests) # objects that actually have doctests
8 9
>>> for t in real_tests: >>> for t in real_tests:
... print('{} {}'.format(len(t.examples), t.name)) ... print('{} {}'.format(len(t.examples), t.name))
... ...
...@@ -675,6 +675,7 @@ plain ol' Python and is guaranteed to be available. ...@@ -675,6 +675,7 @@ plain ol' Python and is guaranteed to be available.
2 builtins.float.hex 2 builtins.float.hex
1 builtins.hex 1 builtins.hex
1 builtins.int 1 builtins.int
3 builtins.int.as_integer_ratio
2 builtins.int.bit_length 2 builtins.int.bit_length
1 builtins.oct 1 builtins.oct
......
...@@ -3,6 +3,7 @@ from test import support ...@@ -3,6 +3,7 @@ from test import support
import sys import sys
import enum
import random import random
import math import math
import array import array
...@@ -1349,6 +1350,37 @@ class LongTest(unittest.TestCase): ...@@ -1349,6 +1350,37 @@ class LongTest(unittest.TestCase):
self.assertEqual(type(value << shift), int) self.assertEqual(type(value << shift), int)
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__": if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -1350,6 +1350,7 @@ Juan M. Bello Rivas ...@@ -1350,6 +1350,7 @@ Juan M. Bello Rivas
Mohd Sanad Zaki Rizvi Mohd Sanad Zaki Rizvi
Davide Rizzo Davide Rizzo
Anthony Roach Anthony Roach
Lisa Roach
Carl Robben Carl Robben
Ben Roberts Ben Roberts
Mark Roberts Mark Roberts
......
Added as_integer_ratio to ints to make them more interoperable with floats.
...@@ -118,6 +118,34 @@ int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored)) ...@@ -118,6 +118,34 @@ int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored))
return int_bit_length_impl(self); 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__, PyDoc_STRVAR(int_to_bytes__doc__,
"to_bytes($self, /, length, byteorder, *, signed=False)\n" "to_bytes($self, /, length, byteorder, *, signed=False)\n"
"--\n" "--\n"
...@@ -211,4 +239,4 @@ int_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyOb ...@@ -211,4 +239,4 @@ int_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyOb
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=fd64beb83bd16df3 input=a9049054013a1b77]*/ /*[clinic end generated code: output=6d5e92d7dc803751 input=a9049054013a1b77]*/
...@@ -5260,6 +5260,36 @@ long_is_finite(PyObject *v) ...@@ -5260,6 +5260,36 @@ long_is_finite(PyObject *v)
} }
#endif #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] /*[clinic input]
int.to_bytes int.to_bytes
...@@ -5392,6 +5422,7 @@ static PyMethodDef long_methods[] = { ...@@ -5392,6 +5422,7 @@ static PyMethodDef long_methods[] = {
#endif #endif
INT_TO_BYTES_METHODDEF INT_TO_BYTES_METHODDEF
INT_FROM_BYTES_METHODDEF INT_FROM_BYTES_METHODDEF
INT_AS_INTEGER_RATIO_METHODDEF
{"__trunc__", long_long_meth, METH_NOARGS, {"__trunc__", long_long_meth, METH_NOARGS,
"Truncating an Integral returns itself."}, "Truncating an Integral returns itself."},
{"__floor__", long_long_meth, METH_NOARGS, {"__floor__", long_long_meth, METH_NOARGS,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment