]> granicus.if.org Git - python/commitdiff
Issue #18844: Make the number of selections a keyword-only argument for random.choices().
authorRaymond Hettinger <python@rcn.com>
Tue, 27 Sep 2016 04:45:57 +0000 (21:45 -0700)
committerRaymond Hettinger <python@rcn.com>
Tue, 27 Sep 2016 04:45:57 +0000 (21:45 -0700)
Doc/library/random.rst
Lib/random.py
Lib/test/test_random.py
Misc/NEWS

index 5eb44da5b4abb0d1b108192324d7f0cb9cb986a7..9cb145e36c15ca526e1da266b39fb47450d74410 100644 (file)
@@ -124,7 +124,7 @@ Functions for sequences:
    Return a random element from the non-empty sequence *seq*. If *seq* is empty,
    raises :exc:`IndexError`.
 
-.. function:: choices(k, population, weights=None, *, cum_weights=None)
+.. function:: choices(population, weights=None, *, cum_weights=None, k=1)
 
    Return a *k* sized list of elements chosen from the *population* with replacement.
    If the *population* is empty, raises :exc:`IndexError`.
index cd8583fe4a31e6242920c3afe6b4c62b245e1992..ef8cb05601831a13147fdfc78d239e8553d01d66 100644 (file)
@@ -337,7 +337,7 @@ class Random(_random.Random):
                 result[i] = population[j]
         return result
 
-    def choices(self, k, population, weights=None, *, cum_weights=None):
+    def choices(self, population, weights=None, *, cum_weights=None, k=1):
         """Return a k sized list of population elements chosen with replacement.
 
         If the relative weights or cumulative weights are not specified,
index 9c1383d7db57376327389e77305c4b516194b34c..0dfc290824a39a28680640a0b24a945da00b1d93 100644 (file)
@@ -151,8 +151,8 @@ class TestBasicOps:
 
         # basic functionality
         for sample in [
-            choices(5, data),
-            choices(5, data, range(4)),
+            choices(data, k=5),
+            choices(data, range(4), k=5),
             choices(k=5, population=data, weights=range(4)),
             choices(k=5, population=data, cum_weights=range(4)),
         ]:
@@ -164,50 +164,50 @@ class TestBasicOps:
         with self.assertRaises(TypeError):                               # missing arguments
             choices(2)
 
-        self.assertEqual(choices(0, data), [])                           # k == 0
-        self.assertEqual(choices(-1, data), [])                          # negative k behaves like ``[0] * -1``
+        self.assertEqual(choices(data, k=0), [])                         # k == 0
+        self.assertEqual(choices(data, k=-1), [])                        # negative k behaves like ``[0] * -1``
         with self.assertRaises(TypeError):
-            choices(2.5, data)                                           # k is a float
+            choices(data, k=2.5)                                         # k is a float
 
-        self.assertTrue(set(choices(5, str_data)) <= set(str_data))      # population is a string sequence
-        self.assertTrue(set(choices(5, range_data)) <= set(range_data))  # population is a range
+        self.assertTrue(set(choices(str_data, k=5)) <= set(str_data))    # population is a string sequence
+        self.assertTrue(set(choices(range_data, k=5)) <= set(range_data))  # population is a range
         with self.assertRaises(TypeError):
-            choices(2.5, set_data)                                       # population is not a sequence
+            choices(set_data, k=2)                                       # population is not a sequence
 
-        self.assertTrue(set(choices(5, data, None)) <= set(data))        # weights is None
-        self.assertTrue(set(choices(5, data, weights=None)) <= set(data))
+        self.assertTrue(set(choices(data, None, k=5)) <= set(data))      # weights is None
+        self.assertTrue(set(choices(data, weights=None, k=5)) <= set(data))
         with self.assertRaises(ValueError):
-            choices(5, data, [1,2])                                      # len(weights) != len(population)
+            choices(data, [1,2], k=5)                                    # len(weights) != len(population)
         with self.assertRaises(IndexError):
-            choices(5, data, [0]*4)                                      # weights sum to zero
+            choices(data, [0]*4, k=5)                                    # weights sum to zero
         with self.assertRaises(TypeError):
-            choices(5, data, 10)                                         # non-iterable weights
+            choices(data, 10, k=5)                                       # non-iterable weights
         with self.assertRaises(TypeError):
-            choices(5, data, [None]*4)                                   # non-numeric weights
+            choices(data, [None]*4, k=5)                                 # non-numeric weights
         for weights in [
                 [15, 10, 25, 30],                                                 # integer weights
                 [15.1, 10.2, 25.2, 30.3],                                         # float weights
                 [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional weights
                 [True, False, True, False]                                        # booleans (include / exclude)
         ]:
-            self.assertTrue(set(choices(5, data, weights)) <= set(data))
+            self.assertTrue(set(choices(data, weights, k=5)) <= set(data))
 
         with self.assertRaises(ValueError):
-            choices(5, data, cum_weights=[1,2])                          # len(weights) != len(population)
+            choices(data, cum_weights=[1,2], k=5)                        # len(weights) != len(population)
         with self.assertRaises(IndexError):
-            choices(5, data, cum_weights=[0]*4)                          # cum_weights sum to zero
+            choices(data, cum_weights=[0]*4, k=5)                        # cum_weights sum to zero
         with self.assertRaises(TypeError):
-            choices(5, data, cum_weights=10)                             # non-iterable cum_weights
+            choices(data, cum_weights=10, k=5)                           # non-iterable cum_weights
         with self.assertRaises(TypeError):
-            choices(5, data, cum_weights=[None]*4)                       # non-numeric cum_weights
+            choices(data, cum_weights=[None]*4, k=5)                     # non-numeric cum_weights
         with self.assertRaises(TypeError):
-            choices(5, data, range(4), cum_weights=range(4))             # both weights and cum_weights
+            choices(data, range(4), cum_weights=range(4), k=5)           # both weights and cum_weights
         for weights in [
                 [15, 10, 25, 30],                                                 # integer cum_weights
                 [15.1, 10.2, 25.2, 30.3],                                         # float cum_weights
                 [Fraction(1, 3), Fraction(2, 6), Fraction(3, 6), Fraction(4, 6)], # fractional cum_weights
         ]:
-            self.assertTrue(set(choices(5, data, cum_weights=weights)) <= set(data))
+            self.assertTrue(set(choices(data, cum_weights=weights, k=5)) <= set(data))
 
     def test_gauss(self):
         # Ensure that the seed() method initializes all the hidden state.  In
index b5e9a757ee74ad2806a38fd5d093e900e7a6c570..3ce38f8596b5400ebb3ba6d44713128522f112c4 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,10 @@ Library
 - Issue #27897: Fixed possible crash in sqlite3.Connection.create_collation()
   if pass invalid string-like object as a name.  Patch by Xiang Zhang.
 
+- Issue #18844: random.choices() now has k as a keyword-only argument
+  to improve the readability of common cases and the come into line
+  with the signature used in other languages.
+
 - Issue #18893: Fix invalid exception handling in Lib/ctypes/macholib/dyld.py.
   Patch by Madison May.