gh-111881: Import _sha2 lazily in random (#111889)

The random module now imports the _sha2 module lazily in the
Random.seed() method for str, bytes and bytearray seeds. It also
imports lazily the warnings module in the _randbelow() method for
classes without getrandbits(). Lazy import makes Python startup
faster and reduces the number of imported modules at startup.
This commit is contained in:
Victor Stinner 2023-11-09 23:10:21 +01:00 committed by GitHub
parent 0802fd6c8e
commit b9f814ce6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -50,7 +50,6 @@
# Adrian Baddeley. Adapted by Raymond Hettinger for use with
# the Mersenne Twister and os.urandom() core generators.
from warnings import warn as _warn
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 math import tau as TWOPI, floor as _floor, isfinite as _isfinite
@ -63,13 +62,6 @@
import os as _os
import _random
try:
# hashlib is pretty heavy to load, try lean internal module first
from _sha2 import sha512 as _sha512
except ImportError:
# fallback to official implementation
from hashlib import sha512 as _sha512
__all__ = [
"Random",
"SystemRandom",
@ -105,6 +97,7 @@
BPF = 53 # Number of bits in a float
RECIP_BPF = 2 ** -BPF
_ONE = 1
_sha512 = None
class Random(_random.Random):
@ -159,6 +152,16 @@ def seed(self, a=None, version=2):
a = -2 if x == -1 else x
elif version == 2 and isinstance(a, (str, bytes, bytearray)):
global _sha512
if _sha512 is None:
try:
# hashlib is pretty heavy to load, try lean internal
# module first
from _sha2 import sha512 as _sha512
except ImportError:
# fallback to official implementation
from hashlib import sha512 as _sha512
if isinstance(a, str):
a = a.encode()
a = int.from_bytes(a + _sha512(a).digest())
@ -257,9 +260,10 @@ def _randbelow_without_getrandbits(self, n, maxsize=1<<BPF):
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.")
from warnings import warn
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)
rem = maxsize % n
limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0