From: Raymond Hettinger Date: Fri, 5 Sep 2003 21:40:30 +0000 (+0000) Subject: SF bug #801342: Bug (documentation or real, your choice) in random.sample. X-Git-Tag: v2.3.1~84 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0b0aae087a3e3bb9fb109454f6deb2ab171f7eba;p=thirdparty%2FPython%2Fcpython.git SF bug #801342: Bug (documentation or real, your choice) in random.sample. random.sample() uses one of two algorithms depending on the ratio of the sample size to the population size. One of the algorithms accepted any iterable population argument so long as it defined __len__(). The other had a stronger requirement that the population argument be indexable. While it met the documentation specifications which insisted that the population argument be a sequence, it made random.sample() less usable with sets. So, the second algorithm was modified to coerce non-indexable iterables and dictionaries into a tuple before proceeding. --- diff --git a/Lib/random.py b/Lib/random.py index b1d13c0dfb59..11059337f5d9 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -258,6 +258,10 @@ class Random(_random.Random): result[i] = pool[j] pool[j] = pool[n-i-1] # move non-selected item into vacancy else: + try: + n > 0 and (population[0], population[n//2], population[n-1]) + except (TypeError, KeyError): # handle sets and dictionaries + population = tuple(population) selected = {} for i in xrange(k): j = _int(random() * n) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index c9103e8f87b7..a58a1054504a 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -86,6 +86,17 @@ class TestBasicOps(unittest.TestCase): else: self.fail() + def test_sample_inputs(self): + # SF bug #801342 -- population can be any iterable defining __len__() + from sets import Set + self.gen.sample(Set(range(20)), 2) + self.gen.sample(range(20), 2) + self.gen.sample(xrange(20), 2) + self.gen.sample(dict.fromkeys('abcdefghijklmnopqrst'), 2) + self.gen.sample(str('abcdefghijklmnopqrst'), 2) + self.gen.sample(unicode('abcdefghijklmnopqrst'), 2) + self.gen.sample(tuple('abcdefghijklmnopqrst'), 2) + def test_gauss(self): # Ensure that the seed() method initializes all the hidden state. In # particular, through 2.2.1 it failed to reset a piece of state used diff --git a/Misc/NEWS b/Misc/NEWS index 9a9e0f8ff3f0..36e3237c2c52 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -67,6 +67,9 @@ Library allow any iterable. Also the Set.update() has been deprecated because it duplicates Set.union_update(). +- Bug #801342: random.sample() now accepts a Set as a possible argument. + Previously, it insisted that the population argument be indexable. + - Bug #778964: random.seed() now uses fractional seconds so that rapid successive, seeding calls will produce different sequences.