Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a9621bb

Browse files
authored
bpo-42222: Modernize integer test/conversion in randrange() (#23064)
1 parent 1031f23 commit a9621bb

File tree

4 files changed

+81
-11
lines changed

4 files changed

+81
-11
lines changed

Doc/library/random.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ Functions for integers
135135
values. Formerly it used a style like ``int(random()*n)`` which could produce
136136
slightly uneven distributions.
137137

138+
.. deprecated:: 3.10
139+
The automatic conversion of non-integer types to equivalent integers is
140+
deprecated. Currently ``randrange(10.0)`` is losslessly converted to
141+
``randrange(10)``. In the future, this will raise a :exc:`TypeError`.
142+
143+
.. deprecated:: 3.10
144+
The exception raised for non-integral values such as ``range(10.5)``
145+
will be changed from :exc:`ValueError` to :exc:`TypeError`.
146+
138147
.. function:: randint(a, b)
139148

140149
Return a random integer *N* such that ``a <= N <= b``. Alias for

Lib/random.py

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
5252
from os import urandom as _urandom
5353
from _collections_abc import Set as _Set, Sequence as _Sequence
54+
from operator import index as _index
5455
from itertools import accumulate as _accumulate, repeat as _repeat
5556
from bisect import bisect as _bisect
5657
import os as _os
@@ -297,28 +298,59 @@ def randrange(self, start, stop=None, step=1):
297298

298299
# This code is a bit messy to make it fast for the
299300
# common case while still doing adequate error checking.
300-
istart = int(start)
301-
if istart != start:
302-
raise ValueError("non-integer arg 1 for randrange()")
301+
try:
302+
istart = _index(start)
303+
except TypeError:
304+
if int(start) == start:
305+
istart = int(start)
306+
_warn('Float arguments to randrange() have been deprecated\n'
307+
'since Python 3.10 and will be removed in a subsequent '
308+
'version.',
309+
DeprecationWarning, 2)
310+
else:
311+
_warn('randrange() will raise TypeError in the future',
312+
DeprecationWarning, 2)
313+
raise ValueError("non-integer arg 1 for randrange()")
303314
if stop is None:
304315
if istart > 0:
305316
return self._randbelow(istart)
306317
raise ValueError("empty range for randrange()")
307318

308319
# stop argument supplied.
309-
istop = int(stop)
310-
if istop != stop:
311-
raise ValueError("non-integer stop for randrange()")
320+
try:
321+
istop = _index(stop)
322+
except TypeError:
323+
if int(stop) == stop:
324+
istop = int(stop)
325+
_warn('Float arguments to randrange() have been deprecated\n'
326+
'since Python 3.10 and will be removed in a subsequent '
327+
'version.',
328+
DeprecationWarning, 2)
329+
else:
330+
_warn('randrange() will raise TypeError in the future',
331+
DeprecationWarning, 2)
332+
raise ValueError("non-integer stop for randrange()")
333+
334+
try:
335+
istep = _index(step)
336+
except TypeError:
337+
if int(step) == step:
338+
istep = int(step)
339+
_warn('Float arguments to randrange() have been deprecated\n'
340+
'since Python 3.10 and will be removed in a subsequent '
341+
'version.',
342+
DeprecationWarning, 2)
343+
else:
344+
_warn('randrange() will raise TypeError in the future',
345+
DeprecationWarning, 2)
346+
raise ValueError("non-integer step for randrange()")
312347
width = istop - istart
313-
if step == 1 and width > 0:
348+
if istep == 1 and width > 0:
314349
return istart + self._randbelow(width)
315-
if step == 1:
350+
if istep == 1:
316351
raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
317352

318353
# Non-unit step argument supplied.
319-
istep = int(step)
320-
if istep != step:
321-
raise ValueError("non-integer step for randrange()")
322354
if istep > 0:
323355
n = (width + istep - 1) // istep
324356
elif istep < 0:

Lib/test/test_random.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,26 @@ def test_randrange_errors(self):
542542
raises(0, 42, 0)
543543
raises(0, 42, 3.14159)
544544

545+
def test_randrange_argument_handling(self):
546+
randrange = self.gen.randrange
547+
with self.assertWarns(DeprecationWarning):
548+
randrange(10.0, 20, 2)
549+
with self.assertWarns(DeprecationWarning):
550+
randrange(10, 20.0, 2)
551+
with self.assertWarns(DeprecationWarning):
552+
randrange(10, 20, 1.0)
553+
with self.assertWarns(DeprecationWarning):
554+
randrange(10, 20, 2.0)
555+
with self.assertWarns(DeprecationWarning):
556+
with self.assertRaises(ValueError):
557+
randrange(10.5)
558+
with self.assertWarns(DeprecationWarning):
559+
with self.assertRaises(ValueError):
560+
randrange(10, 20.5)
561+
with self.assertWarns(DeprecationWarning):
562+
with self.assertRaises(ValueError):
563+
randrange(10, 20, 1.5)
564+
545565
def test_randbelow_logic(self, _log=log, int=int):
546566
# check bitcount transition points: 2**i and 2**(i+1)-1
547567
# show that: k = int(1.001 + _log(n, 2))
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Harmonized random.randrange() argument handling to match range().
2+
3+
* The integer test and conversion in randrange() now uses
4+
operator.index().
5+
* Non-integer arguments to randrange() are deprecated.
6+
* The *ValueError* is deprecated in favor of a *TypeError*.
7+
* It now runs a little faster than before.
8+
9+
(Contributed by Raymond Hettinger and Serhiy Storchaka.)

0 commit comments

Comments
 (0)