为什么random.choice需要一个列表

时间:2013-06-11 15:12:03

标签: python list

这可能是一个非常直截了当的问题,但是为什么会喜欢一个简单的解释?

以下代码需要一个列表才能获得随机卡。

 import random
 card = random.choice (["hearts", "clubs", "frogs"])

我很困惑为什么它需要一个清单以及为什么我不能这样做。

import = random
card = random.choice("hearts" , "clubs", "frogs")

我很好,我不能这样做我只是想知道为什么?

7 个答案:

答案 0 :(得分:30)

由于墨菲的定律: 您建议的API需要

random.choice(*lst)

当要选择的值在列表(或其他序列)lst中时。有人写的时候

random.choice(lst)
相反,它们总是会返回lst而不是异常。 “显式优于隐式”的Python原则规定我们必须输入一些额外的字符。

(承认,其他人指出random.choice("foobar")的结果对于初学者来说可能会让人感到惊讶,但是一旦你习惯了这种语言,你就会对它的运作方式表示赞赏。)

答案 1 :(得分:8)

问题在于您使用3个参数调用random.choice,而不是使用3个元素调用单个参数。例如,尝试random.choice(('one', 'two', 'three'))

任何具有长度和合适__getitem__(用于索引)的序列都可以 - 因为它选择0到len(something)之间的数字来选择元素。

所以如果你愿意,你可以使用元组。

答案 2 :(得分:7)

因为,第一个片段

["hearts","clubs","frogs"]

只向函数发送一个参数(列表)

而第二个向函数发送三个字符串。函数choice只能使用一个参数。因此,您必须将其作为列表或任何可以编制索引的内容发送,以便它选择随机索引来返回值

答案 3 :(得分:5)

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

答案 4 :(得分:4)

上面有几个很好的答案,关于为什么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)

答案 5 :(得分:2)

看看the implementation。它从0 to len(input_sequence)中选择一个随机数,然后使用该索引选择一个随机项。

也许更好的答案是因为documentation表示输入必须是序列。

答案 6 :(得分:0)

简单地说,因为random.choice函数不是如何定义的。我的猜测是,这个决定只是因为接受一个可迭代的参数比一个可变数量的任意参数更简洁。

因此定义这样的函数:

# This is (approximately) how it's 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]