random.getrandbits / randbytes

getrandbits() is the integer source behind randrange, randint, choice, shuffle and sample. randbytes(n) is just getrandbits(n * 8) written out little-endian. Both are predictable: for secrets use secrets.token_bytes / randbits.

random functiongetrandbits: all Python 3 versions (k=0 since 3.9); randbytes: Python 3.9+Live demo
Common call
random.getrandbits(64)
Returns
int below 2**k / bytes of length n
Replaces
Building ints from several random() calls
Watch out
Up to k bits: leading zero bits make bit_length() smaller
random.getrandbits(k) / random.randbytes(n)
→ int | bytes

Demo

Live evaluation
k random bits as an int, with its bit_length(): never more than k, sometimes less.
Try:
Inputs
seedint | stran int or a string
kintnumber of bits
Code
import random
random.seed(42)
x = random.getrandbits(8)
(x, x.bit_length())
Result
(163, 8)

For k <= 32 one 32-bit Mersenne Twister word is drawn and shifted right, so getrandbits(8) is the top 8 bits of the word. Larger k fills 32-bit words from the least significant end. randbytes(4) after seed 42 is 9d79b1a3, the same word as getrandbits(32) = 0xa3b1799d written little-endian.

Parameters

NameTypeRequiredDescription
kintyesgetrandbits: number of bits, >= 0 (0 allowed since 3.9 and returns 0).
nintyesrandbytes: number of bytes, >= 0.

Return value

int | bytes — getrandbits: an int with 0 <= x < 2**k. randbytes: a bytes object of length n.

Common patterns

A random 64-bit id (non-secret)
Fast, uniform, reproducible with a seed.
import random
row_id = random.getrandbits(64)
label = f'{row_id:016x}'
Random test data
Seeded bytes for fuzzing a parser.
import random
rng = random.Random(1234)
payload = rng.randbytes(1024)
Secure bytes and bits
Same shape, unpredictable source.
import secrets
key = secrets.token_bytes(32)
nonce = secrets.randbits(96)

Examples

1. 8 random bits
import random random.seed(42) random.getrandbits(8)
Returns
163
2. Coin flips as single bits
import random random.seed(42) [random.getrandbits(1) for _ in range(10)]
Returns
[1, 0, 0, 1, 0, 0, 0, 0, 1, 0]
3. A 64-bit value
import random random.seed(42) random.getrandbits(64)
Returns
2053695854357871005
4. k=0 returns 0 (3.9+)
import random random.seed(42) random.getrandbits(0)
Returns
0
5. Eight random bytes
import random random.seed(42) random.randbytes(8)
Returns
b'\x9dy\xb1\xa3\x7f1\x80\x1c'
6. randbytes = getrandbits, little-endian
import random random.seed(42) a = random.randbytes(4) random.seed(42) b = random.getrandbits(32).to_bytes(4, 'little') a == b
Returns
True
7. As a zero-padded hex string
import random random.seed(42) f'{random.getrandbits(32):08x}'
Returns
'a3b1799d'
8. Negative sizes
import random random.getrandbits(-1)
Returns
ValueError: number of bits must be non-negative

Pitfalls

1. Expecting exactly k bits
getrandbits(k) is uniform below 2**k, so the top bits can be 0 and bit_length() is often smaller than k. Pad when you format it.
bit_length()
import random
random.seed(42)
random.getrandbits(256).bit_length()
254
zero-padded
import random
random.seed(42)
len(f'{random.getrandbits(256):0256b}')
256
2. Keys and tokens from randbytes
The docs say randbytes "should not be used for generating security tokens": anyone who knows the seed, or enough outputs, can reproduce it. secrets.token_bytes reads os.urandom.
random.randbytes
import random
random.seed(42)
random.randbytes(4).hex()
'9d79b1a3'
secrets.token_bytes
import secrets
len(secrets.token_bytes(16))
16

When to use

Use it
  • Uniform integers of a given bit width: hashes for tests, ids, bit masks
  • Reproducible random bytes for tests and fuzzing
  • A custom Random subclass: supplying getrandbits enables arbitrarily large randrange
Reach for something else
  • Keys, nonces, tokens, salts → secrets.token_bytes / secrets.randbits
  • An int in a range that is not a power of two → randrange (it rejects out-of-range draws for you)

Notes

CPython impl
getrandbits is C (Modules/_randommodule.c): k <= 32 returns genrand_uint32() >> (32 - k); larger k fills 32-bit words least significant first, trimming the last word. Random.randbytes in Lib/random.py is self.getrandbits(n * 8).to_bytes(n, "little")
Errors
ValueError: number of bits must be non-negative for k < 0 (also randbytes(-1), via n * 8); TypeError for floats
Platforms
Pure integer operations: identical results everywhere

FAQ

random.randbytes(n) (3.9+) for reproducible, non-secret bytes; secrets.token_bytes(n) or os.urandom(n) for anything security related.