3

Python does not have a random.randbool function, although it has randint, randrange and random. If I wanted to use a randbool function, nothing stops me from using the following code:

import random
random.randbool = lambda: random.random() >= 0.5

Is it recommended to do this? Is it 'pythonic'? Is it much slower? This definitely allows for ease of understanding in later code, since instead inlining random.random() >= 0.5 or random.choice([False, True]) could be more confusing.

The alternative is, of course, just using a regular function -

def randbool():
    return random.random() >= 0.5

Which is better?

Edit: Some timeit benchmarks:

> python -m timeit -s "import random" -s "def randbool():" -s " return random.random() >= 0.5" "randbool()
1000000 loops, best of 3: 0.275 usec per loop

> python -m timeit -s "import random" "random.random() >= 0.5"
10000000 loops, best of 3: 0.152 usec per loop

> python -m timeit -s "import random" -s "random.randbool = lambda: random.random() >= 0.5" "random.randbool()"
1000000 loops, best of 3: 0.322 usec per loop

> python -m timeit -s "import random" "random.choice([False, True])"
100000 loops, best of 3: 2.03 usec per loop

> python -m timeit -s "import random" "random.randint(0, 1)"
100000 loops, best of 3: 2.9 usec per loop

So, the fastest is inlining, followed by a regular function, then defining random.randbool. choice and randint are far slower.

Sam McCreery
  • 542
  • 3
  • 18
  • 10
    IMO `random.choice([False, True])` is very elegant and self-explaining. Re. speed: Why don't you test it? – vaultah Nov 25 '15 at 16:19
  • Note also that there are almost no circumstances where you can't use ints 0 and 1 in place of False and True, so randint would be fine. – Daniel Roseman Nov 25 '15 at 16:20
  • 1
    IMO I would never modify a library externally like this in real code. Define it in a utility file or somewhere else, but don't add it to `random`. – Colonel Thirty Two Nov 25 '15 at 16:21
  • 2
    Just wanted to connect to [this answer](http://stackoverflow.com/questions/6824681/get-a-random-boolean-in-python), which also suggests `random.getrandbits(1)`. – Matt Hall Nov 25 '15 at 17:28
  • 1
    This question is very opinion-based and asking several different things, but could most probably be edited into better shape. – TylerH Nov 26 '15 at 09:05

3 Answers3

2

This is somewhat opinion based, but I'll try to back my opinion up a bit.

Patching standard library modules is generally considered bad form - builtins even go so far as to disallow monkey-patching. The main reason I'd not do this is for consistency. If someone else saw your code (or you came back to it later), there's no documentation or specification for random.randbool anywhere that you might think to look. It's misleading, and that sort of goes against python's "explicit is better than implicit" mantra.

Instead, I'd suggest choosing the fastest method (random.random() < .5) and just making a helper function out of it. Since performance seems to be an issue, here's what my machine gives for a few relevant examples:

In [30]: %timeit randbool()
10000000 loops, best of 3: 184 ns per loop

In [31]: %timeit random.random() < .5
10000000 loops, best of 3: 114 ns per loop

In [32]: %timeit random.randint(0,1)
1000000 loops, best of 3: 1.18 µs per loop

And here's what you get if you want some typing with your helper function:

In [33]: %timeit bool(randbool())
1000000 loops, best of 3: 310 ns per loop

Still pretty fast, all in all, even with the overhead of the function call (which you'd get from patching random anyway).

a p
  • 3,098
  • 2
  • 24
  • 46
1

In Ruby quite common is to implement mixins, that enhance methods available for classes from standard library. Lot of Rails stuff is built that way.

But I didn't see any indications that would show that this is good practice in Python. If standard modules lack some feature, it's quite common to create your own module. The advantage of that is you do not to create impression that some function/method comes from standard set for anyone else who may look into your code. I think most Pythonistas trust imports they see at the beginning of the module.

I can't answer if your approach is slower. I had to 'patch' original Python libraries in the past by using meta-programming, but that was done to make sure we have consistent interface for test methods.

Michał Fita
  • 1,183
  • 1
  • 7
  • 24
0

You answered your question:

Whatever is

  1. Easier to read
  2. Faster execute
  3. Shorter to write

is better. This is my priorisation, reorder them in the way that seems right to you and fits your needs.

steffen
  • 8,572
  • 11
  • 52
  • 90