mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-130285: Fix handling of zero or empty counts in random.sample() (gh-130291)
This commit is contained in:
		
							parent
							
								
									0c4248f88e
								
							
						
					
					
						commit
						286c517db0
					
				
					 3 changed files with 21 additions and 5 deletions
				
			
		|  | @ -421,11 +421,11 @@ def sample(self, population, k, *, counts=None): | |||
|             cum_counts = list(_accumulate(counts)) | ||||
|             if len(cum_counts) != n: | ||||
|                 raise ValueError('The number of counts does not match the population') | ||||
|             total = cum_counts.pop() | ||||
|             total = cum_counts.pop() if cum_counts else 0 | ||||
|             if not isinstance(total, int): | ||||
|                 raise TypeError('Counts must be integers') | ||||
|             if total <= 0: | ||||
|                 raise ValueError('Total of counts must be greater than zero') | ||||
|             if total < 0: | ||||
|                 raise ValueError('Counts must be non-negative') | ||||
|             selections = self.sample(range(total), k=k) | ||||
|             bisect = _bisect | ||||
|             return [population[bisect(cum_counts, s)] for s in selections] | ||||
|  |  | |||
|  | @ -225,8 +225,6 @@ def test_sample_with_counts(self): | |||
|             sample(['red', 'green', 'blue'], counts=10, k=10)               # counts not iterable | ||||
|         with self.assertRaises(ValueError): | ||||
|             sample(['red', 'green', 'blue'], counts=[-3, -7, -8], k=2)      # counts are negative | ||||
|         with self.assertRaises(ValueError): | ||||
|             sample(['red', 'green', 'blue'], counts=[0, 0, 0], k=2)         # counts are zero | ||||
|         with self.assertRaises(ValueError): | ||||
|             sample(['red', 'green'], counts=[10, 10], k=21)                 # population too small | ||||
|         with self.assertRaises(ValueError): | ||||
|  | @ -234,6 +232,20 @@ def test_sample_with_counts(self): | |||
|         with self.assertRaises(ValueError): | ||||
|             sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2)      # too many counts | ||||
| 
 | ||||
|         # Cases with zero counts match equivalents without counts (see gh-130285) | ||||
|         self.assertEqual( | ||||
|             sample('abc', k=0, counts=[0, 0, 0]), | ||||
|             sample([], k=0), | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             sample([], 0, counts=[]), | ||||
|             sample([], 0), | ||||
|         ) | ||||
|         with self.assertRaises(ValueError): | ||||
|             sample([], 1, counts=[]) | ||||
|         with self.assertRaises(ValueError): | ||||
|             sample('x', 1, counts=[0]) | ||||
| 
 | ||||
|     def test_choices(self): | ||||
|         choices = self.gen.choices | ||||
|         data = ['red', 'green', 'blue', 'yellow'] | ||||
|  |  | |||
|  | @ -0,0 +1,4 @@ | |||
| Fix corner case for :func:`random.sample` allowing the *counts* parameter to | ||||
| specify an empty population. So now, ``sample([], 0, counts=[])`` and | ||||
| ``sample('abc', k=0, counts=[0, 0, 0])`` both give the same result as | ||||
| ``sample([], 0)``. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Raymond Hettinger
						Raymond Hettinger