-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
bpo-37319: Deprecated support of non-integer arguments in random.randrange(). #19112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
9f81ab8
ccff52e
fb9382e
fcd6549
2e8cfda
d2925e6
6ff20ab
3ad3c36
5749575
d5dec67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,9 +95,10 @@ | |
| LOG4 = _log(4.0) | ||
| SG_MAGICCONST = 1.0 + _log(4.5) | ||
| BPF = 53 # Number of bits in a float | ||
| RECIP_BPF = 2**-BPF | ||
| RECIP_BPF = 2 ** -BPF | ||
| _ONE = 1 | ||
|
|
||
|
|
||
| class Random(_random.Random): | ||
| """Random number generator base class used by bound module functions. | ||
|
|
||
|
|
@@ -213,7 +214,82 @@ def __reduce__(self): | |
| return self.__class__, (), self.getstate() | ||
|
|
||
|
|
||
| def randrange(self, start, stop=None, step=_ONE, _index=_index, _int=int): | ||
| ## ---- internal support method for evenly distributed integers ---- | ||
|
|
||
| def __init_subclass__(cls, /, **kwargs): | ||
| """Control how subclasses generate random integers. | ||
|
|
||
| The algorithm a subclass can use depends on the random() and/or | ||
| getrandbits() implementation available to it and determines | ||
| whether it can generate random integers from arbitrarily large | ||
| ranges. | ||
| """ | ||
|
|
||
| for c in cls.__mro__: | ||
| if '_randbelow' in c.__dict__: | ||
| # just inherit it | ||
| break | ||
| if 'getrandbits' in c.__dict__: | ||
| cls._randbelow = cls._randbelow_with_getrandbits | ||
| break | ||
| if 'random' in c.__dict__: | ||
| cls._randbelow = cls._randbelow_without_getrandbits | ||
| break | ||
|
|
||
| def _randbelow_with_getrandbits(self, n): | ||
| "Return a random int in the range [0,n). Returns 0 if n==0." | ||
|
|
||
| if not n: | ||
| return 0 | ||
| getrandbits = self.getrandbits | ||
| k = n.bit_length() # don't use (n-1) here because n can be 1 | ||
| r = getrandbits(k) # 0 <= r < 2**k | ||
| while r >= n: | ||
| r = getrandbits(k) | ||
| return r | ||
|
|
||
| def _randbelow_without_getrandbits(self, n, maxsize=1<<BPF): | ||
| """Return a random int in the range [0,n). Returns 0 if n==0. | ||
|
|
||
| The implementation does not use getrandbits, but only random. | ||
| """ | ||
|
|
||
| random = self.random | ||
| if n >= maxsize: | ||
| _warn("Underlying random() generator does not supply \n" | ||
| "enough bits to choose from a population range this large.\n" | ||
| "To remove the range limitation, add a getrandbits() method.") | ||
| return _floor(random() * n) | ||
| if n == 0: | ||
| return 0 | ||
| rem = maxsize % n | ||
| limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0 | ||
| r = random() | ||
| while r >= limit: | ||
| r = random() | ||
| return _floor(r * maxsize) % n | ||
|
|
||
| _randbelow = _randbelow_with_getrandbits | ||
|
|
||
|
|
||
| ## -------------------------------------------------------- | ||
| ## ---- Methods below this point generate custom distributions | ||
| ## ---- based on the methods defined above. They do not | ||
| ## ---- directly touch the underlying generator and only | ||
| ## ---- access randomness through the methods: random(), | ||
| ## ---- getrandbits(), or _randbelow(). | ||
|
|
||
|
|
||
| ## -------------------- bytes methods --------------------- | ||
|
|
||
| def randbytes(self, n): | ||
| """Generate n random bytes.""" | ||
| return self.getrandbits(n * 8).to_bytes(n, 'little') | ||
|
|
||
|
|
||
| ## -------------------- integer methods ------------------- | ||
|
|
||
| def randrange(self, start, stop=None, step=_ONE): | ||
| """Choose a random item from range(start, stop[, step]). | ||
|
|
||
| This fixes the problem with randint() which includes the | ||
|
|
@@ -226,7 +302,7 @@ def randrange(self, start, stop=None, step=_ONE, _index=_index, _int=int): | |
| try: | ||
| istart = _index(start) | ||
| except TypeError: | ||
| istart = _int(start) | ||
| istart = int(start) | ||
| if istart != start: | ||
| raise ValueError("non-integer arg 1 for randrange()") | ||
| _warn('non-integer arg 1 for randrange()', | ||
|
|
@@ -240,7 +316,7 @@ def randrange(self, start, stop=None, step=_ONE, _index=_index, _int=int): | |
| try: | ||
| istop = _index(stop) | ||
| except TypeError: | ||
| istop = _int(stop) | ||
| istop = int(stop) | ||
| if istop != stop: | ||
| raise ValueError("non-integer stop for randrange()") | ||
| _warn('non-integer stop for randrange()', | ||
|
|
@@ -256,7 +332,7 @@ def randrange(self, start, stop=None, step=_ONE, _index=_index, _int=int): | |
| try: | ||
| istep = _index(step) | ||
| except TypeError: | ||
| istep = _int(step) | ||
| istep = int(step) | ||
| if istep != step: | ||
| raise ValueError("non-integer step for randrange()") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we're at it, the exception type should be converted to TypeError.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we raise it with custom message or reraise the exception raised by |
||
| _warn('non-integer step for randrange()', | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.