Почему список необходим для 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)

Ответ 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]!