random module
Monty’s random uses CPython’s MT19937 core, ported from Modules/_randommodule.c, with the method bodies of
Lib/random.py ported on top.
A seeded generator produces CPython 3.14’s sequence: random.seed(42) gives the same random(), randint(),
choice(), shuffle(), sample() and choices() results as CPython, and the same distribution values on the same
platform (see the note on floats below).
- Module functions:
random,seed,getstate,setstate,getrandbits,randbytes,randrange,randint,choice,choices,shuffle,sample,uniform,triangular,normalvariate,gauss,lognormvariate,expovariate,vonmisesvariate,gammavariate,betavariate,paretovariate,weibullvariate,binomialvariate. random.Random(x=None)instances with the same methods and an independent state, plusinstance.VERSION.
An unseeded generator seeds itself from the host on its first draw.
The draw suspends with an os.urandom host call for 2496 bytes, the 624 32-bit words of one MT19937 state vector,
and the reply seeds the generator as CPython’s seed(None) does from the same bytes.
This applies to the module-level generator and to a random.Random() created without a seed.
random.seed() and random.seed(None) make the same call.
A host that answers with fixed bytes makes unseeded runs reproducible.
A reply of any other length, or one that is not bytes, raises RuntimeError.
Code that seeds explicitly never calls the host.
Where nothing answers the call, the first unseeded draw raises
RuntimeError: 'os.urandom' is not supported in this environment.
That is the case in a pool session without an os= handler, in one whose handler returns NOT_HANDLED, and in the
monty CLI with a --mount.
In pydantic_monty, AbstractOS.urandom() returns the host’s os.urandom(size) by default.
Under Rust’s non-suspending MontyRun::run, which the CLI uses without a mount, the draw raises
NotImplementedError, as every unanswered OS call does there.
getstate() on a never-seeded generator makes the same call first, since there is no state to report until then.
The module-level generator is session state like the globals: a seed set in one feed_run applies to the next, and
it is included in a dump.
Randominstances do not convert to host values. Returning aRandominstance,random.Randomortype(rng)to the host producesMontyObject::Reprin Rust and a string in Python. Return the generated values orrng.getstate()instead.- No
SystemRandom, andrandom.Randomcannot be subclassed (Monty has no class inheritance, see classes.md).random.Random.VERSIONon the class raisesAttributeError; on an instance it is3. Instances have nogauss_nextattribute. - Instance methods must be called directly, as on other native objects such as
re.Pattern.rng.random()works, butdraw = rng.randomandgetattr(rng, 'random')raiseAttributeError. Module functions can be stored and passed as callbacks:draw = random.randomworks. - Integer ranges are 64-bit.
randrange,randint,choiceandsampleraiseOverflowError: Python int too large to convert to C ssize_tfor bounds outsidei64; CPython accepts any int.seed(big_int)accepts any int, as in CPython.getrandbits(k)raisesOverflowError: Python int too large for C uint64_tfromk >= 2**63, where CPython accepts up to2**64and then fails to allocate;randbytes(n)raises it fromn >= 2**61in both. The sum ofsample(counts=...)must also fit in a signed 64-bit integer. - Seeds.
seed(x)acceptsNone,int,float,strandbytes; there is nobytearray.seed(float('nan'))seeds from0, where CPython hashes the object’s address. Astr/bytesseed with aversionother than1or2is hashed with Monty’s own string hash, where CPython’s hash is randomized per process. - The distributions convert their arguments to float, so a non-number raises
TypeError: must be real number, not strwhere CPython reports the arithmetic that failed (unsupported operand type(s) for -).binomialvariate(n, p)requires an intn. sampleacceptslist,tuple,str,bytes,rangeanddequepopulations only (CPython accepts anycollections.abc.Sequence).kand eachcountsentry must be ints, sosample(x, 1.5)raises'float' object cannot be interpreted as an integerinstead of CPython’s sequence-multiplication error.choicesaccumulatesweightsas floats, so int weights above2**53lose precision;cum_weightsmay be any iterable of numbers.setstateaccepts version 3 and version 2 state tuples; the third element (gauss_next) must beNoneor afloat,intorbool, and is stored as a float, where CPython stores any object. A state word in2**63..2**64is truncated to 32 bits as on 64-bit CPython; CPython on Windows raisesOverflowErrorfor it.- Argument errors on an unseeded generator are raised after the entropy call. Whether a draw needs entropy is
decided before its arguments are parsed, so
random.randint('a')on a never-seeded generator requests entropy from the host and only then raises itsTypeError. CPython seeds at import, so it raises without reading entropy. - Float results match CPython on the same platform. The distributions call the platform’s
log,exp,sin,cosandpow, as CPython does, so values can differ in the last bits between operating systems.binomialvariateuses thelibmcrate’slgammawhere CPython has its own implementation, which can change the outcome of a borderline acceptance test. Float-power overflow messages use glibc’s(34, 'Numerical result out of range')on every platform. - Arity errors do not count
self.random.seed(1, 2, 3)reportstakes from 0 to 2 positional arguments but 3 were givenwhere CPython, calling a bound method, saysfrom 1 to 3 ... but 4.getstate(1)reportstakes no arguments (1 given). randrange(start, None, 1)treats an explicit1step as the default, as CPython does through small-int identity, so it succeeds;Trueis not1there and raisesMissing a non-None stop argumentin both.