我正在阅读 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)
这是怎么回事?我不认为甲板是一个序列。
答案 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)
。