Почему список необходим для random.choice
Это, вероятно, очень прямой вопрос, но он хотел бы просто объяснить, почему?
В приведенном ниже коде требуется список, чтобы получить случайную карту.
import random
card = random.choice (["hearts", "clubs", "frogs"])
Я озадачен тем, почему для этого нужен список и почему я не могу этого сделать.
import = random
card = random.choice("hearts" , "clubs", "frogs")
Я в порядке, что я не могу этого сделать, я просто хотел бы знать, почему?
Ответы
Ответ 1
потому что первый фрагмент
["hearts","clubs","frogs"]
отправляет только один аргумент функции (список)
а второй отправляет три строки в функцию. Функция choice
оснащена только одним аргументом. Таким образом, вы должны отправить его в виде списка или всего, что может быть проиндексировано, так что он выбирает случайный индекс для возврата значения
Ответ 2
Из-за закона Мерфи: все, что может быть сделано неверным путем, будет сделано некорректным путем кем-то, когда-нибудь. Для вашего предлагаемого API потребуется
random.choice(*lst)
когда значения, которые нужно выбрать, находятся в списке (или другой последовательности) lst
. Когда кто-то пишет
random.choice(lst)
вместо этого они всегда получат lst
обратно вместо исключения. Принцип Python, который "явный лучше, чем неявный", затем указывает, что мы должны ввести несколько дополнительных символов.
(Допустим, результат random.choice("foobar")
, отмеченный другими, может быть неожиданным для новичков, но как только вы привыкнете к этому языку, вы поймете, как это работает.)
Ответ 3
Проблема в том, что вы вызываете random.choice
с тремя параметрами, а не с одним параметром с 3 элементами. Попробуйте random.choice(('one', 'two', 'three'))
, например.
Любая последовательность с длиной и подходящим __getitem__
(для индексирования) будет делать, поскольку она выбирает число между 0 и len(something)
для выбора элемента.
Таким образом, вы могли бы использовать кортеж, если хотите.
Ответ 4
random.choice
будет работать для любой последовательности, поддерживающей индексирование.
>>> random.choice("foobar") #string
'o'
>>> random.choice(("foo","bar","spam")) #tuple
'spam'
>>> random.choice(["foo","bar","spam"]) #list
'spam'
Не будет работать для множеств:
>>> random.choice({"foo","bar","spam"})
Traceback (most recent call last):
File "<ipython-input-313-e97c3088a7ef>", line 1, in <module>
random.choice({"foo","bar","spam"})
File "/usr/lib/python2.7/random.py", line 274, in choice
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
TypeError: 'set' object does not support indexing
В random.choice("hearts" , "clubs", "frogs")
вы фактически передали три аргумента choice
, а random.choice
ожидает только один параметр, и это тоже должно поддерживать индексирование.
Но random.choice
может работать для dict, если dict имеет числовые клавиши (от 0 до len (dict) -1), так как внутри он делает что-то вроде этого:
dic[int(random() * len(seq))]
Пример:
>>> dic = dict(zip([1, 2, 3, 4, 5, 6], "abcdef"))
>>> random.choice(dic)
'b'
>>> random.choice(dic)
'd'
>>> random.choice(dic)
'd'
>>> random.choice(dic) #fails as 0 was not found in dic
Traceback (most recent call last):
File "<ipython-input-366-5cfa0e5f2911>", line 1, in <module>
random.choice(dic)
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: 0
Ответ 5
Есть несколько хороших ответов выше о том, почему random.choice
реализовано так, как есть, и почему это на самом деле то, что вы, вероятно, захотите.
Вы можете обернуть его самостоятельно достаточно легко, если хотите, чтобы иметь возможность вызывать выбор с произвольным количеством аргументов:
import random
def random_choice_of_arbitrary_args(*args):
return random.choice(args)
Конечно, вы, вероятно, назовете его более кратким.
Это имеет следующее удивительное поведение:
>>> random_choice_of_arbitrary_args([1, 2, 3])
[1, 2, 3]
Это потому, что вы в конечном счете говорите random.choice, чтобы дать вам случайный элемент последовательности с одним элементом. Таким образом, лучшая реализация может быть:
import random
def my_choice(*args):
if len(args) == 1:
return random.choice(args[0])
else:
return random.choice(args)
Ответ 6
Посмотрите реализацию. Он выбирает случайное число из 0 to len(input_sequence)
, а затем использует этот индекс для выбора случайного элемента.
Возможно, лучший ответ заключается в том, что документация говорит, что вход должен быть последовательностью.
Ответ 7
Проще говоря, потому что это не так, как была определена функция random.choice
. Я предполагаю, что решение было принято только потому, что принятие одного итерабельного аргумента - более чистая практика, чем просто переменное количество произвольных аргументов.
Поэтому, определяя функцию следующим образом:
# This is (approximately) how it actually written
def choice(iterable):
#choose from iterable
чище, чем это:
# This is kind of ugly
def choice(*args):
#make sure *args exists, choose from among them.
То, как оно написано на самом деле, позволяет передать ему один единственный истребимый элемент любого типа, который является чистым и удобным. Если бы он был определен вторым способом, при использовании его было бы легко испортить: кто-то мог вызвать random.choice([1, 2, 3])
, и они всегда вернутся назад [1, 2, 3]
!