[Python-ideas] Python's Source of Randomness and the random.py module Redux

Nick Coghlan ncoghlan at gmail.com
Thu Sep 10 19:00:22 CEST 2015


On 11 September 2015 at 02:05, Brett Cannon <brett at python.org> wrote:
> +1 for deprecating module-level functions and putting everything into
> classes to force a choice

-1000, as this would be a *huge* regression in Python's usability for
educational use cases. (Think 7-8 year olds that are still learning to
read, not teenagers or adults with more fully developed vocabularies)

A reasonable "Hello world!" equivalent for introducing randomness to
students is rolling a 6-sided die, as that relates to a real world
object they'll often be familiar with. At the moment that reads as
follows:

>>> from random import randint
>>> randint(1, 6)
6
>>> randint(1, 6)
3
>>> randint(1, 6)
1
>>> randint(1, 6)
4

Another popular educational exercise is the "Guess a number" game,
where the program chooses a random number from 1-100, and the person
playing the game has to guess what it is. Again, randint() works fine
here.

Shuffling decks of cards, flipping coins, these are all things used to
introduce learners to modelling random events in the real world in
software, and we absolutely do *not* want to invalidate the extensive
body of educational material that assumes the current module level API
for the random module.

> +0 for deprecating the seed-related functions and saying "the stdlib uses
> was it uses as a RNG and you have to live with it if you don't make your own
> choice" and switching to a crypto-secure RNG.

However, this I'm +1 on. People *do* use the module level APIs
inappropriately, and we can get them to a much safer place, while
nudging folks that genuinely need deterministic randomness towards an
alternative API.

The key for me is that folks that actually *need* deterministic
randomness *will* be calling the stateful module level APIs. This
means we can put the deprecation warnings on *those* methods, and
leave them out for the others.

In terms of practical suggestions, rather than DeterministicRandom and
NonDeterministicRandom, I'd actually go with the simpler terms
SeededRandom and SeedlessRandom (there's a case to be made that those
are misnomers, but I'll go into that more below):

SeededRandom: Mersenne Twister
SeedlessRandom: new CSPRNG
SystemRandom: os.urandom()

Phase one of transition:

* add SeedlessRandom
* rename Random to SeededRandom
* Random becomes a subclass of SeededRandom that deprecates all
methods not shared with SeedlessRandom
* this will also effectively deprecate the corresponding module level functions
* any SystemRandom methods that are no-ops (like seed()) are deprecated

Phase two of transition:

* Random becomes an alias for SeedlessRandom
* deprecated methods are removed from SystemRandom
* deprecated module level functions are removed

As far as the proposed Seeded/Seedless naming goes, that deliberately
glosses over the fact that "seed" gets used to refer to two different
things - seeding a PRNG with entropy, and seeding a deterministic PRNG
with a particular seed value. The key is that "SeedlessRandom" won't
have a "seed()" *method*, and that's the single most salient fact
about it from a user experience perspective: you can't get the same
output by providing the same seed value, because we wouldn't let you
provide a seed value at all.

Regards,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list