diff options
author | Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de> | 2018-04-17 17:16:17 +0200 |
---|---|---|
committer | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2018-04-17 08:16:17 -0700 |
commit | ba3a87aca37cec5b1ee32cf68f4a254fa0bb2bec (patch) | |
tree | 4352a84a350b5170a7ec2c519e4c49906b8bc339 /Lib/random.py | |
parent | Fix spelling typo (GH-6443) (diff) | |
download | cpython-ba3a87aca37cec5b1ee32cf68f4a254fa0bb2bec.tar.gz cpython-ba3a87aca37cec5b1ee32cf68f4a254fa0bb2bec.tar.bz2 cpython-ba3a87aca37cec5b1ee32cf68f4a254fa0bb2bec.zip |
bpo-33144: random.Random and subclasses: split _randbelow implementation (GH-6291)
Diffstat (limited to 'Lib/random.py')
-rw-r--r-- | Lib/random.py | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/Lib/random.py b/Lib/random.py index 0bc24174e13..0ed5511e9f6 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -38,7 +38,6 @@ General notes on the underlying Mersenne Twister core generator: """ from warnings import warn as _warn -from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin from os import urandom as _urandom @@ -94,6 +93,28 @@ class Random(_random.Random): self.seed(x) self.gauss_next = None + 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. + """ + + if (cls.random is _random.Random.random) or ( + cls.getrandbits is not _random.Random.getrandbits): + # The original random() builtin method has not been overridden + # or a new getrandbits() was supplied. + # The subclass can use the getrandbits-dependent implementation + # of _randbelow(). + cls._randbelow = cls._randbelow_with_getrandbits + else: + # There's an overridden random() method but no new getrandbits(), + # so the subclass can only use the getrandbits-independent + # implementation of _randbelow(). + cls._randbelow = cls._randbelow_without_getrandbits + def seed(self, a=None, version=2): """Initialize internal state from hashable object. @@ -221,22 +242,23 @@ class Random(_random.Random): return self.randrange(a, b+1) - def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type, - Method=_MethodType, BuiltinMethod=_BuiltinMethodType): + def _randbelow_with_getrandbits(self, n): "Return a random int in the range [0,n). Raises ValueError if n==0." - random = self.random getrandbits = self.getrandbits - # Only call self.getrandbits if the original random() builtin method - # has not been overridden or if a new getrandbits() was supplied. - if type(random) is BuiltinMethod or type(getrandbits) is Method: - 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 - # There's an overridden random() method but no new getrandbits() method, - # so we can only use random() from here. + 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, int=int, maxsize=1<<BPF): + """Return a random int in the range [0,n). Raises ValueError 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" @@ -251,6 +273,8 @@ class Random(_random.Random): r = random() return int(r*maxsize) % n + _randbelow = _randbelow_with_getrandbits + ## -------------------- sequence methods ------------------- def choice(self, seq): |