random.sample

No position is picked twice, so k can be at most len(population). It works on any sequence including huge ranges (sample(range(10**12), 3) is instant), but sets and dicts must be converted first since Python 3.11.

random functionAll Python 3 versions (counts= 3.9+, sets rejected since 3.11)Live demo
Common call
random.sample(range(1, 50), 6)
Returns
list of k distinct positions of the population
Replaces
shuffle a copy and slice it
Watch out
sample(a_set, k) → TypeError since 3.11: use sorted(a_set)
random.sample(populationpopulation — list, tuple, str or range (a range is never expanded). Not a set or dict.type: Sequence · required, kk — Sample size, 0 <= k <= len(population); otherwise ValueError.type: int · required, *, countscounts — Keyword-only (3.9+). Repeat counts per element: sample(["red", "blue"], counts=[4, 2], k=5) samples from four reds and two blues.type: Sequence[int] · default: None=None)
→ list

Demo

Live evaluation
k distinct picks. With k equal to the length you get a shuffled copy; one more is an error.
Try:
Inputs
seedint | stran int or a string
itemslist[str]comma-separated items
kintsample size
Code
import random
random.seed(42)
random.sample(['a', 'b', 'c', 'd', 'e'], 3)
Result
['a', 'e', 'c']

For a small population sample() copies it into a pool and swaps each pick out; for a large one (here range(1000000)) it keeps a set of chosen indexes and redraws on a collision, so memory stays proportional to k. counts=[4, 2] behaves like the list red, red, red, red, blue, blue: k=7 is too large for those six, and the counts must add up to an int.

Parameters

NameTypeRequiredDescription
populationSequenceyeslist, tuple, str or range (a range is never expanded). Not a set or dict.
kintyesSample size, 0 <= k <= len(population); otherwise ValueError.
countsSequence[int]no (None)Keyword-only (3.9+). Repeat counts per element: sample(["red", "blue"], counts=[4, 2], k=5) samples from four reds and two blues.

Return value

list — A new list of k elements; the population is left unchanged.

Common patterns

Lottery numbers
Distinct numbers, sorted for display.
import random
ticket = sorted(random.sample(range(1, 50), 6))
Train / test split
Pick test indexes without repeats, the rest is training data.
import random
test_idx = set(random.sample(range(len(rows)), k=len(rows) // 5))
test = [r for i, r in enumerate(rows) if i in test_idx]
train = [r for i, r in enumerate(rows) if i not in test_idx]
Shuffled copy of an immutable sequence
The docs recommend this instead of shuffle() for tuples and strings.
import random
scrambled = ''.join(random.sample(word, k=len(word)))
Sample from a set or dict
Sort first so the result is repeatable under a seed.
import random
winners = random.sample(sorted(entrants), 3)

Examples

1. Three distinct letters
import random random.seed(42) random.sample(['a', 'b', 'c', 'd', 'e'], 3)
Returns
['a', 'e', 'c']
2. Six lottery numbers
import random random.seed(42) random.sample(range(1, 50), 6)
Returns
[41, 8, 2, 18, 16, 15]
3. counts= stands for repeats
import random random.seed(42) random.sample(['red', 'blue'], counts=[4, 2], k=5)
Returns
['blue', 'red', 'blue', 'red', 'red']
4. Huge ranges are fine
import random random.seed(42) random.sample(range(10 ** 12), 3)
Returns
[123005401501, 811856239313, 267469214295]
5. Winners in selection order
import random random.seed(42) winners = random.sample(['ann', 'bob', 'cy', 'dee', 'eve'], 3) (winners[0], winners[1:])
Returns
('ann', ['eve', 'cy'])
6. Repeated values can repeat
import random random.seed(42) random.sample([1, 1, 2], 3)
Returns
[2, 1, 1]
7. k larger than the population
import random random.sample([1, 2, 3], 5)
Returns
ValueError: Sample larger than population or is negative

Pitfalls

1. Sampling a set (3.11+)
Automatic conversion of sets was removed in 3.11. Convert explicitly; sorted() also makes the result reproducible, because set iteration order can change between runs.
sample(set, 2)
import random
random.seed(42)
random.sample({'a', 'b', 'c'}, 2)
TypeError: Population must be a sequence. For dicts or sets, use sorted(d).
sample(sorted(set), 2)
import random
random.seed(42)
random.sample(sorted({'a', 'b', 'c'}), 2)
['c', 'a']
2. Forgetting k
Unlike choices(), k has no default: sample() always needs the size.
sample(seq)
import random
random.seed(42)
random.sample(['a', 'b', 'c', 'd'])
TypeError: Random.sample() missing 1 required positional argument: 'k'
sample(seq, k=2)
import random
random.seed(42)
random.sample(['a', 'b', 'c', 'd'], k=2)
['a', 'd']

When to use

Use it
  • Picks without repeats: lottery, raffle, random subset, test split
  • Sampling from a huge range without building it
  • A shuffled copy of an immutable sequence: sample(seq, k=len(seq))
Reach for something else
  • Picks with repeats or weights → choices()
  • Shuffling a list in place → shuffle()
  • Security-relevant selection → secrets.SystemRandom().sample()

Notes

CPython impl
Lib/random.py: setsize = 21, plus 4 ** ceil(log(k * 3, 4)) for k > 5; if n <= setsize it copies the population into a pool and moves each pick out, otherwise it tracks chosen indexes in a set and redraws collisions. Picks come from _randbelow (exact integers), so results are identical on every platform
counts=
Implemented as sample(range(total), k) followed by bisect into the running totals; in 3.12 all-zero counts raised "Total of counts must be greater than zero", 3.13 allows them (and k=0 then returns [])
Order
The result is in selection order, so any slice of it is itself a random sample

FAQ

random.sample(range(start, stop), k) returns k different integers from start to stop - 1, e.g. random.sample(range(1, 50), 6) for six lottery numbers.