我要做的是制作一副纸牌,然后将特定的卡从牌组移到玩家手上。我可以毫不费力地创建牌组并将牌添加到牌手的手中,但每当我尝试从牌组中取出牌时,它就会告诉我卡片不在牌组中,这没有任何意义。
以下是相关代码
class Card(object):
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"] #so zero returns nothing, an Ace is 1 and so forth
def __init__(self, suit, rank): #initial method, just defines suit and rank so you can find it later
self.suit = suit
self.rank = rank
def getRank(self): #returns the rank of the card as an integer
return self.rank
def getSuit(self): #returns suit as an integer
return self.suit
def __str__(self):
return '%s of %s' % (Card.rank_names[self.rank], Card.suit_names[self.suit])
class Deck(object):
def __init__(self): #this is just creating a deck of cards, in standard order with the suits arranged alphabetically
self.cards = []
for suit in range(4):
for rank in range(1, 14):
card=Card(suit, rank)
self.cards.append(card) #what you should be ending up here is 52 objects from the "Card" class
def shuffle(self):
shuffle(self.cards)
def main():
selfHand=[]
s,r=eval(input("Input your first downcard's suit and rank, separated by a comma" ))
card=Card(s,r)
selfHand.append(card)
deck.cards.remove(card)
再次,一切正常工作(我省略了不相关的代码,如果有什么看起来有点 - 这就是为什么主函数中有大的缩进)但最后一行提示错误“ValueError:list。 remove(x):x不在列表中“
要明确的是,牌组应该是一张牌。我试图从甲板上移除一张特定的卡片,就是这样。认为这很简单,但已经吃了一整个下午(公平地说,我对python和编码很新)
此时我尝试了无数种不同的方法,结果相似。
感谢您的帮助
答案 0 :(得分:3)
你在main中创建的新卡与甲板上阵列中的任何卡都不是同一个对象,即使它与其中一张卡具有相同的套装和等级。
>>> c = Card(0,3)
>>> d = Card(0,3)
>>> c
<__main__.Card object at 0x0000000002025978>
>>> d
<__main__.Card object at 0x0000000002025908>
>>> c == d
False
您需要覆盖Card类中的equals而不是equals方法,以便它知道如何比较两个Card实例。
def __eq__(self, other):
if isinstance(other, Card):
return self.suit == other.getSuit() and self.rank == other.getRank()
return NotImplemented
def __ne__(self, other):
if isinstance(other, Card):
return self.suit != other.getSuit() or self.rank != other.getRank()
return NotImplemented
然后你会得到你想要的输出:
>>> c = Card(0,3)
>>> d = Card(0,3)
>>> e = Card(1,4)
>>> c == d
True
>>> c != d
False
>>> c == e
False
>>> c != e
True
>>> deck = Deck()
>>> len(deck.cards)
52
>>> deck.cards.remove(c)
>>> len(deck.cards)
51
答案 1 :(得分:1)
问题在于,当您创建card = Card(s,r)
时,Card(s,r)
对象实际上不在牌组中(因此ValueError
)。我知道它应该是,但这就是为什么它不是:
每次创建时都会创建一个新的Card
,该卡在内存中的位置将不同(即它们是不同的对象)。你可以这样看:
card1 = Card(0, 2)
card2 = Card(0, 2)
assert not card1 is card2 # i.e. id(card1) != id(card2)
所以,从Python的角度来看,你新创建的卡实际上并不在牌组中。要解决此问题,您需要至少覆盖__eq__
和__ne__
方法,以便在比较Card
对象时让Python使用您所认为的“相等”:
def __eq__(self, other):
if isinstance(other, Card):
return self.suit == other.getSuit() and self.rank == other.getRank()
return NotImplemented
def __ne__(self, other):
return not self.__eq__(other)
但是,如Python documentation中所述,“唯一必需的属性是比较相等的对象具有相同的哈希值”。这是为了确保您的Card
类与hashable集合中的项目一样正常工作。因此,覆盖__hash__
方法是个好主意;或许,像这样:
def __hash__(self):
return hash((self.suit, self.rank))
答案 2 :(得分:0)
没有甲板对象。假设你也解决了这个问题,你仍然会遇到问题,因为牌组没有你试图从牌组中移除的卡牌对象。它们是两个不同的对象,即使它们具有相同的参数。为了解决这个问题,我将在deck中添加一个方法,用于搜索给定套装和编号的卡片列表,并专门删除它以避免破坏抽象障碍。此外,这更像是一个技术说明,但您可以通过使用列表解析替换您拥有的内容,使 init 方法更简单(可能更高效):
def __init__(self):
self.cards = [ Card(suit, rank) for rank in range(1 14) for suit in range(4) ]
希望有所帮助。
答案 3 :(得分:0)
我正在进行一些代码审查以帮助您开始使用python,我删除了您的评论(不要说什么,顺便说出原因),并添加了我自己的评论。
import random # don't forget the module for shuffle
class Card(object):
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"] # Start with your first one, you could then iterate over this list instead of from 1 up to but not including 14.
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def getRank(self): # why not use Python's builtin property for getters?
return self.rank
def getSuit(self):
return self.suit
def __str__(self):
return '%s of %s' % (Card.rank_names[self.rank], Card.suit_names[self.suit])
class Deck(object):
def __init__(self):
self.cards = []
for suit in range(4): # 0-3, again, Pythonic to iterate over the list,
for rank in range(1, 14): # 1-13, why start with 1 here, and 0 with suit?
card=Card(suit, rank)
self.cards.append(card)
def shuffle(self):
random.shuffle(self.cards) # call shuffle from the random module,
def main():
selfHand=[]
s,r=input("Input your first downcard's suit and rank, separated by a comma" )
card=Card(s,r)# here you're creating a new card, why not find it in the deck?
selfHand.append(card)
deck.cards.remove(card) # and this deletes the old card, you'll need to be careful to put it back if you do this again.
所以我可能会这样做:
import random # don't forget the module for shuffle
class Card(object):
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit, rank):
self._suit = Card.suit_names.index(suit)
self._rank = Card.rank_names.index(rank)
@property # Python's built-in property, treat rank as an attribute!
def rank(self):
return Card.rank_names[self._rank]
@property
def suit(self):
return Card.suit_names[self._suit]
def __repr__(self): # this will reproduce a card, and will echo on your REPL
return 'Card(%s, %s)' % (self.rank, self.suit) # see how we get attrs now?
def __str__(self):
return '%s of %s' % (self.rank, self.suit)
class Deck(object):
def __init__(self):
self.cards = []
for suit in Card.suit_names:
for rank in Card.rank_names:
card=Card(suit, rank)
self.cards.append(card)
def shuffle(self):
random.shuffle(self.cards) # avoid dumping in your namespace where you might overwrite, call shuffle from the random module
def main():
deck = Deck()
selfHand=[]
response=raw_input("Input suit and rank, as in 'Ace of Clubs' or '10 of Hearts'" )
# and now don't create and delete more cards so the accounting is easier.
deck_str = [str(c) for c in deck.cards]
selfHand.append(deck.cards.pop(deck_str.index(response)))
print selfHand
print 'response not in deck_str:', response not in deck_str
当我输入Ace of Clubs
时:
[Card(Ace, Clubs)]
response not in deck.cards: True