如何将random.choice应用到我的自定义类?

时间:2017-09-05 07:17:35

标签: python python-3.x

我正在阅读 Fluent Python

代码1-1,这里它构造了一个带有namedtuples的类,并实现了__len____getitem__

import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])


class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for rank in self.ranks for suit in self.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

但后来作者使用random.choice从卡片中选择卡片

from random import choice
deck = FrenchDeck()
choice(deck)
这是怎么回事?我不认为甲板是一个序列。

3 个答案:

答案 0 :(得分:2)

random.choice从非空序列中获取随机元素。如果您实施__getitem__python can use that to treat your object as a sequence by indexing以及它的功能。

答案 1 :(得分:1)

实施__getitem__使您的类可迭代。观看:

>>> class LegacyIterable(object):
...     def __init__(self):
...         self._list = ['a', 'b', 'c']
...     def __getitem__(self, item):
...         return self._list[item]
... 
>>> x = LegacyIterable()
>>> for e in x:
...     print e
... 
a
b
c

如果某个类没有__iter__方法而只有__getitem__方法,那么Python在被强制执行时会从试图通过{{1}访问其元素的实例构造一个迭代器。 }。它从索引0开始,一旦抛出__getitem__就结束。

但是,由于IndexError个实例没有LegacyIterable方法,因此它们正式不计入序列,__len__会抱怨

random.choice

但是,一旦我们给它一个TypeError: object of type 'LegacyIterable' has no len() 方法实例计为序列,那就是__len__根据其文档所需的全部内容。

random.choice
  

随机选择(self,seq)方法。随机实例
      从非空序列中选择一个随机元素。

答案 2 :(得分:0)

deck确实不是documentation所述的列表,其类实现__getitem__的任何对象都可以视为类似列表的对象,例如一个序列。由于实施__getitem__允许您使用deck[i]之类的内容,因此您可以调用choice(deck),因为choice(deck)所做的是它会在0和{{1}之间生成一个随机数i }并返回len(deck)