我定义了一个类,它包含一个对象的列表集合,并定义了__iter__和__next__方法,使其可循环。这里的集合是一个Deck类,它包含Card对象的列表。
代码:
import random
class Card:
@staticmethod
def get_ranks():
return ("A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3", "2") # A is highest, 2 is lowest
@staticmethod
def get_suites():
return ("H", "D", "S", "C")
def __init__(self, suite, rank):
if suite not in Card.get_suites():
raise Exception("Invalid suite")
if rank not in Card.get_ranks():
raise Exception("Invalid rank")
self.suite = suite
self.rank = rank
def __lt__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank > card2_rank
def __le__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank >= card2_rank
def __gt__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank < card2_rank
def __ge__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank <= card2_rank
def __eq__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank == card2_rank
def __ne__(self, card2):
self_rank = Card.get_ranks().index(self.rank)
card2_rank = Card.get_ranks().index(card2.rank)
return self_rank != card2_rank
def __str__(self):
return(self.rank + self.suite)
def __repr__(self):
return str(self)
class Deck:
def __init__(self):
self.contents = [Card(suite, rank) for suite in Card.get_suites() for rank in Card.get_ranks()]
random.shuffle(self.contents)
self.index = 0
def __len__(self):
return len(self.contents)
def __iter__(self):
return self
def __next__(self):
if self.index == len(self.contents):
raise StopIteration
item = self.contents[self.index]
self.index += 1
return item
def pick_card(self):
choice = random.randrange(len(self))
card = self.contents.pop(choice)
return card
def return_card_and_shuffle(self, card):
self.contents.append(card)
random.shuffle(self.contents)
def __str__(self):
dstr = ''
for card in self:
dstr += str(card) + ", "
return "{} cards: ".format(len(self)) + dstr[:-2]
def deal_bookends(deck):
card1 = deck.pick_card()
card2 = deck.pick_card()
if card1 > card2:
temp = card1
card1 = card2
card2 = temp
return (card1, card2)
if __name__ == '__main__':
deck = Deck()
for _ in range(3):
c1, c2 = deal_bookends(deck)
print("We have {} and {}".format(c1, c2))
print(deck)
deck.return_card_and_shuffle(c1)
print(deck)
print(deck.contents[-4:])
deck.return_card_and_shuffle(c2)
print(deck)
print(deck.contents[-4:])在运行时,我得到以下错误:
We have 8H and KH
50 cards: 9H, 8C, AC, 7C, 6H, 2S, 2D, 5C, 10H, 5H, JS, 5S, KD, JH, JC, QS, 2H, 3H, 3S, 3D, 4C, 4H, AD, KS, JD, QH, 10D, 6S, 5D, 8D, 3C, 6C, 7D, AS, 7H, AH, 9S, 10C, QC, QD, 7S, 2C, KC, 8S, 4D, 4S, 6D, 10S, 9D, 9C
51 cards: QS
[7D, 5C, 10H, QS]
52 cards: 10C
[KC, 3S, 9H, 10C]
We have 2C and QD
Traceback (most recent call last):
File "playing_cards.py", line 106, in <module>
print(deck)
File "playing_cards.py", line 88, in __str__
for card in self:
File "playing_cards.py", line 73, in __next__
item = self.contents[self.index]
IndexError: list index out of range当我将card对象推回列表时,对于for循环的第二次运行,事情似乎不是这样的。如何在保持pop、push功能的同时解决这个问题。
编辑:self.index在第一次调用print()之后是50。当卡片被添加到列表中时,索引保持在50,而牌长现在是51张。因此,在第二次(和第三次)调用打印最后一张卡片是打印,而不是整个甲板。然后引发随后的错误。
我想我在这里读错了文档。我的问题是,我是否应该在StopIteration位重新设置索引。这是正确的方法,还是索引应该自己重置?
发布于 2018-01-22 05:58:03
注意:如果您想通过实现自己的迭代器来学习迭代器的工作方式,那么上面的建议就成立了。如果您只想使您的Deck可迭代,可以在Deck中这样做。
def __iter__(self):
return self.contents # lists are already iterable更好的是,如果您希望您的甲板表现为一个列表(迭代、索引、切片、删除),您只需扩展list。
学习迭代器的工作方式:
这里的问题是将集合与迭代器混为一谈。集合应该包含一组项。您的Deck是一个集合。集合是可迭代的,这意味着我可以对它执行for x in collection。当我们执行for x in collection时,Python实际上执行for x in iter(collection),它将集合转换为迭代器。
您希望迭代器和集合是分开的。如果集合是它自己的迭代器,那么每次只能有一个迭代器(本身)。还要注意迭代器应该只使用一次。通过在self.index = 0中执行__iter__,可以使迭代器(Deck)可重用。
请考虑以下几点:
nums = [1, 2, 3]
for i in nums:
for j in nums:
print(i, j)我们期待着这一局面的回归:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3注意,每次内部循环迭代整个集合。如果nums是它自己的迭代器,那么我们就会遇到一些问题:
# Here internally nums sets the current index as 0
for i in nums:
# Here internally nums sets the current index as 0 again
for j in nums:
print(i, j)
# Once this inner loop finishes the current index is 4.
# But that is also the index for the outer loop, so the
# outer loop ends too意外产出:
1 1
1 2
1 3解决方案是Deck.__iter__应该返回一个名为DeckIterator的新对象,它跟踪自己的index。DeckIterator.__iter__应该返回self (作为医生要求的),但这只是一个细节。通过这样做,您可以同时在甲板上启用多个迭代,这些迭代按预期的方式工作。
因此,最起码的例子是:
class Deck:
# ... snip ...
def __iter__(self):
return DeckIterator(self.contents)
class DeckIterator:
def __init__(self, cards):
self.index = 0
self.cards = cards
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.cards):
# We've gotten the end of the deck/list
raise StopIteration
item = self.cards[self.index]
self.index += 1
return item另外,如果您不相信这个列表是它自己的迭代器,那么下面的列表显示了这种糟糕的行为:
class BadList(list):
def __iter__(self):
self._current_index = 0
return self
def __next__(self):
print(f'current index is {self._current_index}', end='')
if self._current_index >= len(self):
print(' which is the end, so ending iteration')
raise StopIteration
item = self[self._current_index]
print(f' so returning value {item}')
self._current_index += 1
return item
# Using letters instead of numbers so difference between indices
# and items is more clear
letters = BadList('abc')
for i in letters:
for j in letters:
print(i, j)它的产出:
current index is 0 so returning value "a"
current index is 0 so returning value "a"
a a
current index is 1 so returning value "b"
a b
current index is 2 so returning value "c"
a c
current index is 3 which is the end, so ending iteration
current index is 3 which is the end, so ending iteration发布于 2018-01-22 05:42:12
不知道你是怎么做到的,但你已经超出了名单的长度。建议您比较列表的>=长度,如下所示:
def __next__(self):
if self.index >= len(self.contents):
raise StopIteration
.....发布于 2018-01-22 05:44:04
做以下改变,
def __iter__(self):
self.index = 0
return self这样,每次调用__iter__时,都会重置index。您获得此错误的原因是,一旦您遍历deck,在迭代结束时,self.index == len(self.contents)。
下次迭代时,应该将self.index重置为0。
我做了以上的改变,它对我起作用。
https://stackoverflow.com/questions/48375250
复制相似问题