From f19af2f9e93797c9ae1abbd5c60b1fd995b70897 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 9 Nov 2023 15:22:11 +0100 Subject: [PATCH 1/2] gh-111881: Use lazy imports in the random module 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. --- Lib/random.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Lib/random.py b/Lib/random.py index 3f7bfd272d65a5..9d1960880f6201 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -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", @@ -159,6 +151,14 @@ def seed(self, a=None, version=2): a = -2 if x == -1 else x elif version == 2 and isinstance(a, (str, bytes, bytearray)): + 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 +257,10 @@ def _randbelow_without_getrandbits(self, n, maxsize=1<= 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 From 2811604600fdd4375cc706af3da1e6c60eb6e487 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 9 Nov 2023 16:52:31 +0100 Subject: [PATCH 2/2] Use a global variable for _sha512 --- Lib/random.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/random.py b/Lib/random.py index 9d1960880f6201..875beb2f8cf41c 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -97,6 +97,7 @@ BPF = 53 # Number of bits in a float RECIP_BPF = 2 ** -BPF _ONE = 1 +_sha512 = None class Random(_random.Random): @@ -151,13 +152,15 @@ def seed(self, a=None, version=2): a = -2 if x == -1 else x elif version == 2 and isinstance(a, (str, bytes, bytearray)): - 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 + 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()