Document which part of the random module module are guaranteed.

This commit is contained in:
Raymond Hettinger 2010-09-07 00:38:15 +00:00
parent 435cb0f233
commit f763a728ad
4 changed files with 44 additions and 12 deletions

View File

@ -51,18 +51,23 @@ from sources provided by the operating system.
Bookkeeping functions:
.. function:: seed([x])
.. function:: seed([x], version=2)
Initialize the basic random number generator. Optional argument *x* can be any
:term:`hashable` object. If *x* is omitted or ``None``, current system time is used;
current system time is also used to initialize the generator when the module is
first imported. If randomness sources are provided by the operating system,
they are used instead of the system time (see the :func:`os.urandom` function
for details on availability).
Initialize the random number generator.
If *x* is not ``None`` or an int, ``hash(x)`` is used instead. If *x* is an
int, *x* is used directly.
If *x* is omitted or ``None``, the current system time is used. If
randomness sources are provided by the operating system, they are used
instead of the system time (see the :func:`os.urandom` function for details
on availability).
If *x* is an int, it is used directly.
With version 2 (the default), a :class:`str`, :class:`bytes`, or :class:`bytearray`
object gets converted to a :class:`int` and all of its bits are used. With version 1,
the :func:`hash` of *x* is used instead.
.. versionchanged:: 3.2
Moved to the version 2 scheme which uses all of the bits in a string seed.
.. function:: getstate()

View File

@ -91,13 +91,17 @@ class Random(_random.Random):
self.seed(x)
self.gauss_next = None
def seed(self, a=None):
def seed(self, a=None, version=2):
"""Initialize internal state from hashable object.
None or no argument seeds from current time or from an operating
system specific randomness source if available.
If a is not None or an int, hash(a) is used instead.
For version 2 (the default), all of the bits are used if a is a str,
bytes, or bytearray. For version 1, the hash() of a is used instead.
If a is an int, all bits are used.
"""
if a is None:
@ -107,6 +111,11 @@ class Random(_random.Random):
import time
a = int(time.time() * 256) # use fractional seconds
if version == 2 and isinstance(a, (str, bytes, bytearray)):
if isinstance(a, str):
a = a.encode("utf8")
a = int(_hexlify(a), 16)
super().seed(a)
self.gauss_next = None

View File

@ -39,7 +39,7 @@ class TestBasicOps(unittest.TestCase):
self.gen.seed(arg)
for arg in [list(range(3)), dict(one=1)]:
self.assertRaises(TypeError, self.gen.seed, arg)
self.assertRaises(TypeError, self.gen.seed, 1, 2)
self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4)
self.assertRaises(TypeError, type(self.gen), [])
def test_sample(self):
@ -223,6 +223,21 @@ class SystemRandom_TestBasicOps(TestBasicOps):
class MersenneTwister_TestBasicOps(TestBasicOps):
gen = random.Random()
def test_guaranteed_stable(self):
# These sequences are guaranteed to stay the same across versions of python
self.gen.seed(3456147, version=1)
self.assertEqual([self.gen.random().hex() for i in range(4)],
['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1',
'0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1'])
self.gen.seed("the quick brown fox", version=1)
self.assertEqual([self.gen.random().hex() for i in range(4)],
['0x1.9ee265c177cdep-2', '0x1.bad51092e3c25p-1',
'0x1.85ff833f71576p-1', '0x1.87efb37462927p-1'])
self.gen.seed("the quick brown fox", version=2)
self.assertEqual([self.gen.random().hex() for i in range(4)],
['0x1.1294009b9eda4p-2', '0x1.2ff96171b0010p-1',
'0x1.459e0989bd8e0p-5', '0x1.8b5f55892ddcbp-1'])
def test_setstate_first_arg(self):
self.assertRaises(ValueError, self.gen.setstate, (1, None, None))

View File

@ -18,6 +18,9 @@ Library
* Document which parts of the module are guaranteed to stay the same
across versions and which parts are subject to change.
* Update the seed() method to use all of the bits in a string
instead of just the hash value.
- collections.OrderedDict now supports a new method for repositioning
keys to either end.