random.choices

The weighted pick: weights=[80, 15, 5] makes the first item 16 times as likely as the last. k must be passed by keyword, items can repeat, and the result is a list even for k=1.

random functionPython 3.6+Live demo
Common call
random.choices(['a', 'b'], weights=[3, 1], k=10)
Returns
list of k items (with replacement)
Replaces
Hand-written cumulative-probability loops
Watch out
choices(pop, 3) treats 3 as weights → TypeError; write k=3
random.choices(populationpopulation — What to pick from: list, tuple, str or range. Empty raises IndexError.type: Sequence · required, weightsweights — Relative weights, one per element (int, float or Fraction; not Decimal). Same length as population; the total must be > 0 and finite.type: Sequence[number] · default: None=None, *, cum_weightscum_weights — Keyword-only. Cumulative weights instead, e.g. [10, 15, 45, 50] for weights [10, 5, 30, 5]; saves the internal accumulate step. Not together with weights.type: Sequence[number] · default: None=None, kk — Keyword-only. How many picks. 0 or negative gives [].type: int · default: 1=1)
→ list

Demo

Live evaluation
k picks where every item is equally likely. Repeats are normal.
Try:
Inputs
seedint | stran int or a string
itemslist[str]comma-separated items
kintnumber of picks
Code
import random
random.seed(42)
random.choices(['red', 'green', 'blue'], k=5)
Result
['green', 'red', 'red', 'red', 'blue']

With weights 5, 3, 2 and seed 42 the 1000 picks split 480 / 308 / 212, close to the 500 / 300 / 200 the weights predict. Weights 0.5, 0.25, 0.25 have the same ratios as 2, 1, 1, and a weight of 0 means that item is never picked. If all weights are 0 there is nothing to choose: ValueError.

Parameters

NameTypeRequiredDescription
populationSequenceyesWhat to pick from: list, tuple, str or range. Empty raises IndexError.
weightsSequence[number]no (None)Relative weights, one per element (int, float or Fraction; not Decimal). Same length as population; the total must be > 0 and finite.
cum_weightsSequence[number]no (None)Keyword-only. Cumulative weights instead, e.g. [10, 15, 45, 50] for weights [10, 5, 30, 5]; saves the internal accumulate step. Not together with weights.
kintno (1)Keyword-only. How many picks. 0 or negative gives [].

Return value

list — A new list of k elements of population; repeats are possible.

Common patterns

Loot table or A/B split
Weights as percentages or any relative numbers.
import random
variant = random.choices(['A', 'B'], weights=[90, 10])[0]
Bootstrap resampling
Resample a dataset with replacement, same size as the original.
import random
from statistics import fmean
means = sorted(fmean(random.choices(data, k=len(data))) for _ in range(1000))
Reuse cumulative weights
Accumulate once when you draw from the same weights many times.
import random
from itertools import accumulate
cum = list(accumulate(weights))
batch = random.choices(items, cum_weights=cum, k=10_000)
One weighted item
choices always returns a list; take [0] for a single pick.
import random
winner = random.choices(names, weights=tickets)[0]

Examples

1. k picks, repeats allowed
import random random.seed(42) random.choices(['red', 'green', 'blue'], k=5)
Returns
['green', 'red', 'red', 'red', 'blue']
2. Weighted: 1 win in 10
import random random.seed(42) random.choices(['win', 'lose'], weights=[1, 9], k=10)
Returns
['lose', 'win', 'lose', 'lose', 'lose', 'lose', 'lose', 'win', 'lose', 'win']
3. cum_weights give the same picks
import random random.seed(42) random.choices(['win', 'lose'], cum_weights=[1, 10], k=10)
Returns
['lose', 'win', 'lose', 'lose', 'lose', 'lose', 'lose', 'win', 'lose', 'win']
4. Six roulette spins
import random random.seed(42) random.choices(['red', 'black', 'green'], [18, 18, 2], k=6)
Returns
['black', 'red', 'red', 'red', 'black', 'black']
5. Counts follow the weights
import random random.seed(42) picks = random.choices(['a', 'b', 'c'], weights=[5, 3, 2], k=1000) {x: picks.count(x) for x in 'abc'}
Returns
{'a': 480, 'b': 308, 'c': 212}
6. k=1 still returns a list
import random random.seed(42) random.choices(['x', 'y'], weights=[0.25, 0.75])
Returns
['y']
7. All weights zero
import random random.choices(['a', 'b'], [0, 0])
Returns
ValueError: Total of weights must be greater than zero

Pitfalls

1. Passing k positionally
The second positional parameter is weights, not k. CPython notices that an int was passed as weights and says so.
choices(pop, 3)
import random
random.seed(42)
random.choices(['a', 'b'], 3)
TypeError: The number of choices must be a keyword argument: k=3
choices(pop, k=3)
import random
random.seed(42)
random.choices(['a', 'b'], k=3)
['b', 'a', 'a']
2. Expecting distinct items
choices samples WITH replacement: 10 picks from 10 values are rarely all different. For a draw without repeats use sample().
choices
import random
random.seed(42)
len(set(random.choices(range(10), k=10)))
6
sample
import random
random.seed(42)
len(set(random.sample(range(10), k=10)))
10
3. One weight per item
weights must have exactly len(population) entries; missing weights are not treated as 0.
2 weights, 3 items
import random
random.seed(42)
random.choices(['a', 'b', 'c'], weights=[1, 2])
ValueError: The number of weights does not match the population
explicit 0
import random
random.seed(42)
random.choices(['a', 'b', 'c'], weights=[1, 2, 0], k=4)
['b', 'a', 'a', 'a']

When to use

Use it
  • Weighted random selection: loot tables, traffic splits, simulations
  • Many picks with replacement in one call (k=...)
  • Bootstrap resampling
Reach for something else
  • Picks without repeats → sample()
  • A single unweighted pick → choice() (exact integer method)
  • Security-relevant choices → secrets.choice()

Notes

CPython impl
Lib/random.py: without weights each pick is population[floor(random() * n)]; with weights it accumulates them (itertools.accumulate), multiplies random() by the float total and bisects (bisect.bisect) into the cumulative list. Only float multiplication and comparisons: identical on every platform
vs choice()
For the same seed, choices(seq) and choice(seq) pick different items: choices uses floor(random() * n), choice uses getrandbits-based _randbelow
Errors
TypeError for both weights and cum_weights; ValueError when the number of weights differs, the total is <= 0 or not finite; IndexError for an empty population

FAQ

random.choices(items, weights=[...], k=n). The weights are relative: [3, 1] means the first item is three times as likely. For a single item use random.choices(items, weights=w)[0].