random.Random

random.randint() and friends are bound methods of one hidden Random() shared by every module in your program. An instance of your own has its own state: seeding it, or other code drawing from the global one, cannot disturb each other.

random classAll Python 3 versions (seed types restricted since 3.11)Live demo
Common call
rng = random.Random(42)
Returns
a generator with all the module functions as methods
Replaces
Seeding the shared global generator
Watch out
Create it once; a new Random(42) per call repeats the first value
random.Random(xx — The seed, passed to self.seed(x). Other types raise TypeError since 3.11.type: None | int | float | str | bytes | bytearray · default: None=None)
→ Random

Demo

Live evaluation
Two instances, two seeds, two independent sequences. Give them the same seed and the sequences match.
Try:
Inputs
seed_aint | strseed of a
seed_bint | strseed of b
Code
import random
a = random.Random(1)
b = random.Random(2)
([a.randint(1, 6) for _ in range(5)], [b.randint(1, 6) for _ in range(5)])
Result
([2, 5, 1, 3, 1], [1, 1, 1, 3, 2])

Random(42) gives 6, 1, 1, 6, 3 whether or not the global generator was reseeded in between, and it is the same sequence random.seed(42) would give the module functions: they are the same class. Two instances with the same seed produce identical sequences; different seeds give unrelated ones.

Parameters

NameTypeRequiredDescription
xNone | int | float | str | bytes | bytearrayno (None)The seed, passed to self.seed(x). Other types raise TypeError since 3.11.

Return value

Random — A new generator seeded with x (os.urandom() when x is None).

Attributes

AttributeTypeMeaning
VERSIONintClass attribute 3: the first item of getstate(), checked by setstate().
gauss_nextfloat | NoneInstance attribute: the second value cached by gauss().

Common patterns

Reproducible component
Accept a seed, keep the generator on the object.
import random
class Dealer:
    def __init__(self, seed=None):
        self.rng = random.Random(seed)
    def deal(self, deck, n):
        return self.rng.sample(deck, n)
One generator per thread
Avoid contention and interleaving on the global generator.
import random
import threading
local = threading.local()
def rng():
    if not hasattr(local, "rng"):
        local.rng = random.Random()
    return local.rng
A custom core generator
Override random() (and ideally getrandbits()); every other method then uses it.
import random
class MyRandom(random.Random):
    def random(self):
        return my_source() / 2 ** 53
    def getrandbits(self, k):
        return my_bits(k)

Examples

1. An independent generator
import random rng = random.Random(42) [rng.randint(1, 6) for _ in range(5)]
Returns
[6, 1, 1, 6, 3]
2. Two streams side by side
import random a = random.Random(1) b = random.Random(2) ([a.randint(1, 6) for _ in range(5)], [b.randint(1, 6) for _ in range(5)])
Returns
([2, 5, 1, 3, 1], [1, 1, 1, 3, 2])
3. Same algorithm as the module
import random rng = random.Random(42) random.seed(42) rng.random() == random.random()
Returns
True
4. Seed later with .seed()
import random r = random.Random() r.seed(42) r.random()
Returns
0.6394267984578837
5. Subclass and add methods
import random class Dice(random.Random): def roll(self): return self.randint(1, 6) d = Dice(42) [d.roll() for _ in range(5)]
Returns
[6, 1, 1, 6, 3]
6. Pickle keeps the position
import random import pickle rng = random.Random(42) rng.random() clone = pickle.loads(pickle.dumps(rng)) rng.random() == clone.random()
Returns
True
7. Random.VERSION
import random random.Random.VERSION
Returns
3

Pitfalls

1. A new seeded generator on every call
Each Random(42) starts the same sequence again, so a function that builds one per call returns the same "random" value forever. Create it once and reuse it.
Random(42) per call
import random
def roll():
    return random.Random(42).randint(1, 6)
[roll() for _ in range(5)]
[6, 6, 6, 6, 6]
one instance
import random
rng = random.Random(42)
def roll():
    return rng.randint(1, 6)
[roll() for _ in range(5)]
[6, 1, 1, 6, 3]
2. Seeding the module and expecting an instance to follow
random.seed() only reseeds the hidden global instance. Your own Random keeps its state until you call its own seed().
random.seed(42)
import random
rng = random.Random(1)
random.seed(42)
rng.random() == 0.6394267984578837
False
rng.seed(42)
import random
rng = random.Random(1)
rng.seed(42)
rng.random() == 0.6394267984578837
True

When to use

Use it
  • Library and test code that needs reproducible randomness without touching the global generator
  • Several independent streams (per player, per thread, per simulation run)
  • Subclassing to plug in another core generator
Reach for something else
  • Security → secrets, or SystemRandom
  • Quick scripts where the module functions are enough

Notes

CPython impl
random.Random (Lib/random.py) subclasses _random.Random (Modules/_randommodule.c, the Mersenne Twister). random() and getrandbits() are inherited from the C base, which is why vars(random.Random) does not list them; seed, getstate, setstate and every distribution are defined in Python
Subclassing
__init_subclass__ picks the integer method: a subclass that defines getrandbits() keeps exact _randbelow; one that only defines random() falls back to a float-based _randbelow
Module functions
random.random, random.seed, random.randint … are bound methods of the instance random._inst created at import

FAQ

The class that implements the Mersenne Twister generator. The module-level functions are methods of one hidden instance; random.Random(seed) creates another, independent one with the same methods (randint, choice, shuffle, gauss, …).