Python - 从列表中删除对象

时间:2014-05-11 21:57:28

标签: python list class object

我要做的是制作一副纸牌,然后将特定的卡从牌组移到玩家手上。我可以毫不费力地创建牌组并将牌添加到牌手的手中,但每当我尝试从牌组中取出牌时,它就会告诉我卡片不在牌组中,这没有任何意义。

以下是相关代码

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和编码很新)

此时我尝试了无数种不同的方法,结果相似。

感谢您的帮助

4 个答案:

答案 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