以下是Luciano Romalho的“Fluent Python”中的一副牌。 我希望我复制代码是可以的,我真的没有比这更简洁的类示例。
import collections
from random import choice
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 suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
所以,这个类的一个实例将有52张卡片,每张卡片都是“卡片”对象中定义的命名元组。
我想画一张n张牌,以便它会反映在牌组中。
我尝试了以下内容:
def a_hand(deck, size):
the_hand = []
for n in range(size):
c = choice(deck)
the_hand.append(c)
deck = [i for i in deck if i != c]
return the_hand
所以当我尝试时:
>> deck = FrenchDeck()
>> a = a_hand(deck, 5)
我伸出手,但甲板上没有动过:
>> hand
[Card(rank='9', suit='spades'),
Card(rank='A', suit='hearts'),
Card(rank='2', suit='diamonds'),
Card(rank='8', suit='clubs'),
Card(rank='10', suit='hearts')]
>> len(deck)
52
当我直接在interperter中尝试时:
>> c = choice(deck)
>> alt = [i for i in deck if i != c]
它有效:
>> len(alt)
51
我理解这是因为FrenchDeck的实例不受函数a_hand范围内发生的事情的影响。
这样做的方法是什么?我试图在类中定义一个dunder-delitem函数但是没有把它弄好,也不确定这是否是正确使用的函数以及它是在Card对象还是在FrenchDeck对象中定义的。
答案 0 :(得分:1)
由于FrenchDeck
实例未在a_hand
函数内修改,因此您是对的。相反,您只能覆盖deck
变量。为了实现您的目标,您可以例如将deal_hand
方法添加到FrenchDeck
类,这将返回给定大小的手并从卡片本身中删除选定的卡片。
答案 1 :(得分:1)
您创建一个新牌组而不是更新现有牌组。
deck = [i for i in deck if i != c]
这将创建一个由列表推导构建的 new 列表,并使deck
指向它,而不是指向传递的原始列表。
如果要更改现有列表,则需要使用deck.remove(...)
。
(另外:尝试制作套牌和手牌,而不是列表。它更好地匹配域名。)
答案 2 :(得分:1)
你真的需要移动a_hand
成为FrenchDeck
的方法:
class FrenchDeck:
# All previous code here, plus:
def a_hand(self, size):
the_hand = []
for n in range(size):
c = choice(self._cards)
the_hand.append(c)
self._cards.remove(c)
return the_hand
答案 3 :(得分:1)
当您从牌组中取出牌时,也要将其从牌组中取出。在list.pop
中使用__getitem__
。
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 suit in self.suits
for rank in self.ranks]
def __len__(self):
print(f'__len__ called: {len(self._cards)}')
return len(self._cards)
def __getitem__(self, position):
print(f'getting item {position}')
return self._cards.pop(position)
def a_hand(deck, size):
the_hand = []
for n in range(size):
print('getting another card')
c = choice(deck)
the_hand.append(c)
return the_hand
deck = FrenchDeck()
a = a_hand(deck, 5)