https://github.com/python/cpython/commit/a6bc60da02ea37f33d5abe5e7028fb0876110b76
commit: a6bc60da02ea37f33d5abe5e7028fb0876110b76
branch: main
author: Raymond Hettinger <[email protected]>
committer: rhettinger <[email protected]>
date: 2026-01-12T17:55:02-06:00
summary:
Update random combinatoric recipes and add tests (gh-143762)
files:
M Doc/library/random.rst
diff --git a/Doc/library/random.rst b/Doc/library/random.rst
index 6bddf575a809a1..4c37a69079dcd6 100644
--- a/Doc/library/random.rst
+++ b/Doc/library/random.rst
@@ -634,11 +634,12 @@ from the combinatoric iterators in the :mod:`itertools`
module
or the :pypi:`more-itertools` project:
.. testcode::
+
import random
- def random_product(*args, repeat=1):
- "Random selection from itertools.product(*args, **kwds)"
- pools = [tuple(pool) for pool in args] * repeat
+ def random_product(*iterables, repeat=1):
+ "Random selection from itertools.product(*iterables, repeat=repeat)"
+ pools = tuple(map(tuple, iterables)) * repeat
return tuple(map(random.choice, pools))
def random_permutation(iterable, r=None):
@@ -663,15 +664,89 @@ or the :pypi:`more-itertools` project:
return tuple(pool[i] for i in indices)
def random_derangement(iterable):
- "Choose a permutation where no element is in its original position."
+ "Choose a permutation where no element stays in its original position."
seq = tuple(iterable)
if len(seq) < 2:
- raise ValueError('derangements require at least two values')
- perm = list(seq)
+ if not seq:
+ return ()
+ raise IndexError('No derangments to choose from')
+ perm = list(range(len(seq)))
+ start = tuple(perm)
while True:
random.shuffle(perm)
- if all(p != q for p, q in zip(seq, perm)):
- return tuple(perm)
+ if all(p != q for p, q in zip(start, perm)):
+ return tuple([seq[i] for i in perm])
+
+.. doctest::
+ :hide:
+
+ >>> import random
+
+
+ >>> random.seed(8675309)
+ >>> random_product('ABCDEFG', repeat=5)
+ ('D', 'B', 'E', 'F', 'E')
+
+
+ >>> random.seed(8675309)
+ >>> random_permutation('ABCDEFG')
+ ('D', 'B', 'E', 'C', 'G', 'A', 'F')
+ >>> random_permutation('ABCDEFG', 5)
+ ('A', 'G', 'D', 'C', 'B')
+
+
+ >>> random.seed(8675309)
+ >>> random_combination('ABCDEFG', 7)
+ ('A', 'B', 'C', 'D', 'E', 'F', 'G')
+ >>> random_combination('ABCDEFG', 6)
+ ('A', 'B', 'C', 'D', 'F', 'G')
+ >>> random_combination('ABCDEFG', 5)
+ ('A', 'B', 'C', 'E', 'F')
+ >>> random_combination('ABCDEFG', 4)
+ ('B', 'C', 'D', 'G')
+ >>> random_combination('ABCDEFG', 3)
+ ('B', 'E', 'G')
+ >>> random_combination('ABCDEFG', 2)
+ ('E', 'G')
+ >>> random_combination('ABCDEFG', 1)
+ ('C',)
+ >>> random_combination('ABCDEFG', 0)
+ ()
+
+
+ >>> random.seed(8675309)
+ >>> random_combination_with_replacement('ABCDEFG', 7)
+ ('B', 'C', 'D', 'E', 'E', 'E', 'G')
+ >>> random_combination_with_replacement('ABCDEFG', 3)
+ ('A', 'B', 'E')
+ >>> random_combination_with_replacement('ABCDEFG', 2)
+ ('A', 'G')
+ >>> random_combination_with_replacement('ABCDEFG', 1)
+ ('E',)
+ >>> random_combination_with_replacement('ABCDEFG', 0)
+ ()
+
+
+ >>> random.seed(8675309)
+ >>> random_derangement('')
+ ()
+ >>> random_derangement('A')
+ Traceback (most recent call last):
+ ...
+ IndexError: No derangments to choose from
+ >>> random_derangement('AB')
+ ('B', 'A')
+ >>> random_derangement('ABC')
+ ('C', 'A', 'B')
+ >>> random_derangement('ABCD')
+ ('B', 'A', 'D', 'C')
+ >>> random_derangement('ABCDE')
+ ('B', 'C', 'A', 'E', 'D')
+ >>> # Identical inputs treated as distinct
+ >>> identical = 20
+ >>> random_derangement((10, identical, 30, identical))
+ (20, 30, 10, 20)
+
The default :func:`.random` returns multiples of 2⁻⁵³ in the range
*0.0 ≤ x < 1.0*. All such numbers are evenly spaced and are exactly
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]