random.choice broken with dicts

2019-06-27 20:07发布

问题:

There is a restriction on random.choice that the input must be a sequence. This causes non-obvious and hairy behaviour on a dict:

>>> d = {0: 'spam', 1: 'eggs', 3: 'potato'}
>>> random.choice(d)
'spam'
>>> random.choice(d)
'eggs'
>>> random.choice(d)
'spam'
>>> random.choice(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/random.py", line 274, in choice
    return seq[int(self.random() * len(seq))]  # raises IndexError if seq is empty
KeyError: 2

Additionally it doesn't work at all on a set, and some other containers in collections module.

Aside from my opinion that this implementation of random.choice is balls (there is no good reason why random.choice(d) shouldn't just work in the obvious way), what is a pythonic way to get a random choice from a non-sequence collection?

I considered random.choice(list(d)) and random.sample(d, 1)[0] but hope there may be other less ugly methods.

Can random.choice be monkey-patched to 'just work' while not breaking or drastically reducing efficiency of the current behaviour on sequences?

回答1:

You can see this thread on the Python bug tracker from 2006 about random.choice not working for sets. It's algorithmically possible to make it work with the same asymptotic efficiency, but it would require either custom support from the set/dict data structures, or a new method in the interface. The python devs don't deem it needed.