summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/random.rst9
-rw-r--r--Lib/random.py54
-rw-r--r--Lib/test/test_random.py20
-rw-r--r--Misc/NEWS.d/next/Library/2020-10-31-10-28-32.bpo-42222.Cfl1eR.rst9
4 files changed, 81 insertions, 11 deletions
diff --git a/Doc/library/random.rst b/Doc/library/random.rst
index fa5c74b..07ee011 100644
--- a/Doc/library/random.rst
+++ b/Doc/library/random.rst
@@ -135,6 +135,15 @@ Functions for integers
values. Formerly it used a style like ``int(random()*n)`` which could produce
slightly uneven distributions.
+ .. deprecated:: 3.10
+ The automatic conversion of non-integer types to equivalent integers is
+ deprecated. Currently ``randrange(10.0)`` is losslessly converted to
+ ``randrange(10)``. In the future, this will raise a :exc:`TypeError`.
+
+ .. deprecated:: 3.10
+ The exception raised for non-integral values such as ``range(10.5)``
+ will be changed from :exc:`ValueError` to :exc:`TypeError`.
+
.. function:: randint(a, b)
Return a random integer *N* such that ``a <= N <= b``. Alias for
diff --git a/Lib/random.py b/Lib/random.py
index 66433ba..a4128c2 100644
--- a/Lib/random.py
+++ b/Lib/random.py
@@ -51,6 +51,7 @@ from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
from os import urandom as _urandom
from _collections_abc import Set as _Set, Sequence as _Sequence
+from operator import index as _index
from itertools import accumulate as _accumulate, repeat as _repeat
from bisect import bisect as _bisect
import os as _os
@@ -297,28 +298,59 @@ class Random(_random.Random):
# This code is a bit messy to make it fast for the
# common case while still doing adequate error checking.
- istart = int(start)
- if istart != start:
- raise ValueError("non-integer arg 1 for randrange()")
+ try:
+ istart = _index(start)
+ except TypeError:
+ if int(start) == start:
+ istart = int(start)
+ _warn('Float arguments to randrange() have been deprecated\n'
+ 'since Python 3.10 and will be removed in a subsequent '
+ 'version.',
+ DeprecationWarning, 2)
+ else:
+ _warn('randrange() will raise TypeError in the future',
+ DeprecationWarning, 2)
+ raise ValueError("non-integer arg 1 for randrange()")
if stop is None:
if istart > 0:
return self._randbelow(istart)
raise ValueError("empty range for randrange()")
# stop argument supplied.
- istop = int(stop)
- if istop != stop:
- raise ValueError("non-integer stop for randrange()")
+ try:
+ istop = _index(stop)
+ except TypeError:
+ if int(stop) == stop:
+ istop = int(stop)
+ _warn('Float arguments to randrange() have been deprecated\n'
+ 'since Python 3.10 and will be removed in a subsequent '
+ 'version.',
+ DeprecationWarning, 2)
+ else:
+ _warn('randrange() will raise TypeError in the future',
+ DeprecationWarning, 2)
+ raise ValueError("non-integer stop for randrange()")
+
+ try:
+ istep = _index(step)
+ except TypeError:
+ if int(step) == step:
+ istep = int(step)
+ _warn('Float arguments to randrange() have been deprecated\n'
+ 'since Python 3.10 and will be removed in a subsequent '
+ 'version.',
+ DeprecationWarning, 2)
+ else:
+ _warn('randrange() will raise TypeError in the future',
+ DeprecationWarning, 2)
+ raise ValueError("non-integer step for randrange()")
width = istop - istart
- if step == 1 and width > 0:
+ if istep == 1 and width > 0:
return istart + self._randbelow(width)
- if step == 1:
+ if istep == 1:
raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
# Non-unit step argument supplied.
- istep = int(step)
- if istep != step:
- raise ValueError("non-integer step for randrange()")
if istep > 0:
n = (width + istep - 1) // istep
elif istep < 0:
diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py
index e7f911d..436f3c9 100644
--- a/Lib/test/test_random.py
+++ b/Lib/test/test_random.py
@@ -542,6 +542,26 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
raises(0, 42, 0)
raises(0, 42, 3.14159)
+ def test_randrange_argument_handling(self):
+ randrange = self.gen.randrange
+ with self.assertWarns(DeprecationWarning):
+ randrange(10.0, 20, 2)
+ with self.assertWarns(DeprecationWarning):
+ randrange(10, 20.0, 2)
+ with self.assertWarns(DeprecationWarning):
+ randrange(10, 20, 1.0)
+ with self.assertWarns(DeprecationWarning):
+ randrange(10, 20, 2.0)
+ with self.assertWarns(DeprecationWarning):
+ with self.assertRaises(ValueError):
+ randrange(10.5)
+ with self.assertWarns(DeprecationWarning):
+ with self.assertRaises(ValueError):
+ randrange(10, 20.5)
+ with self.assertWarns(DeprecationWarning):
+ with self.assertRaises(ValueError):
+ randrange(10, 20, 1.5)
+
def test_randbelow_logic(self, _log=log, int=int):
# check bitcount transition points: 2**i and 2**(i+1)-1
# show that: k = int(1.001 + _log(n, 2))
diff --git a/Misc/NEWS.d/next/Library/2020-10-31-10-28-32.bpo-42222.Cfl1eR.rst b/Misc/NEWS.d/next/Library/2020-10-31-10-28-32.bpo-42222.Cfl1eR.rst
new file mode 100644
index 0000000..2f570bb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-10-31-10-28-32.bpo-42222.Cfl1eR.rst
@@ -0,0 +1,9 @@
+Harmonized random.randrange() argument handling to match range().
+
+* The integer test and conversion in randrange() now uses
+ operator.index().
+* Non-integer arguments to randrange() are deprecated.
+* The *ValueError* is deprecated in favor of a *TypeError*.
+* It now runs a little faster than before.
+
+(Contributed by Raymond Hettinger and Serhiy Storchaka.)