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.
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
| Name | Type | Required | Description |
|---|---|---|---|
| k | int | yes | getrandbits: number of bits, >= 0 (0 allowed since 3.9 and returns 0). |
| n | int | yes | randbytes: 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
1632. 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
20536958543578710054. k=0 returns 0 (3.9+)
import random
random.seed(42)
random.getrandbits(0)
Returns
05. 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
True7. 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-negativePitfalls
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.