random.choice
принимает одну последовательность. У вас есть несколько вариантов того, как сгенерировать нужное число.
Чтобы исправить немедленную ошибку, сделайте входные данные последовательностью:
value = r.choice([r.randint(10, 30), r.randint(50, 100)])
Это не очень хорошее решение потому что он генерирует два числа, что расточительно. Кроме того, результирующее распределение зависит от размеров диапазонов, что, вероятно, неверно.
Более общий способ решить эту проблему - сгенерировать одно число и отобразить его в желаемом диапазоне:
v = r.randint(0, 21 + 51)
value = v + 10 if v <= 20 else v - 21 + 50
Если вы хотите указать входные данные как диапазоны и получить равномерное распределение по всем из них, вы можете обобщить так:
def from_ranges(*ranges):
n = sum(map(len, ranges))
v = random.randrange(n)
for range in ranges:
k = len(range)
if v < k:
return range[v]
v -= k
Это хорошо, потому что диапазоны - это небольшие объекты, которые не занимает много места, но дает вам большую гибкость с точки зрения того, что вы можете указать.
Для примера в вашем вопросе вы бы назвали функцию как
>>> from_ranges(range(10, 31), range(50, 101))
Вы также можете исключить окончательный линейный поиск в пользу бинарного поиска, накапливая длины в кумулятивную сумму:
from bisect import bisect
from itertools import accumulate
from random import randrange
def from_ranges(*ranges):
lengths = list(accumulate(map(len, ranges)))
v = randrange(lengths[-1])
r = bisect(lengths, v)
offset = lengths[r - 1] if r > 0 else 0
return ranges[r][v - offset]
Это решение будет быстрее, если вы запомните накопление до случайное число генерируется. В противном случае он дает небольшое преимущество перед первым решением.