【问题标题】:Python--Removing an Object from a ListPython——从列表中删除对象
【发布时间】:2014-06-29 04:29:52
【问题描述】:

我要做的是制作一副牌,然后将一张特定牌从牌组移到玩家手上。我在创建牌组并将牌添加到玩家手上时没有问题,但是每当我尝试从牌组中取出牌时,它都会告诉我牌一开始不在牌组中,这是没有意义的。

这里是相关代码

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)

再次,一切正常(我省略了不相关的代码,如果有什么看起来有点不对劲——这就是为什么 main 函数中有大缩进)但最后一行提示错误“ValueError: list. remove(x): x 不在列表中"

明确地说,套牌应该是一张卡片列表。我正试图从牌组中取出一张特定的牌,就是这样。认为这很简单,但已经吃掉了整个下午(公平地说,我对 python 和编码很陌生)

在这一点上,我尝试了无数不同的方法,结果相似。

感谢您的帮助

【问题讨论】:

  • 您发布的代码使用了一个未定义的对象deck
  • 我假设您有一个 deck = Deck(),但您忘记在此处添加?
  • 我采取了使用 Python 2 进行代码审查的方法,它有帮助吗?您使用的是哪个版本的 Python?

标签: python list class object


【解决方案1】:

没有甲板对象。假设你也解决了这个问题,你仍然会遇到问题,因为牌组没有你试图从牌组中移除的相同的卡片对象。它们是两个不同的对象,即使它们具有相同的参数。为了解决这个问题,我会在套牌中添加一个方法,该方法将在卡片列表中搜索给定的花色和数字,并专门删除它以避免破坏抽象障碍。此外,这更像是一个技术说明,但您可以通过将您拥有的内容替换为列表理解来使您的 init 方法更简单(可能更有效):

def __init__(self):
     self.cards = [ Card(suit, rank) for rank in range(1 14) for suit in range(4) ]

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    您在 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 和 not 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
    

    【讨论】:

    • 如果您覆盖__eq__,通常最好也覆盖__hash__;在这种情况下是有道理的。
    【解决方案3】:

    问题是当您创建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__ 方法,以便 Python 在比较 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):
        return not self.__eq__(other)
    

    而且,正如Python documentation 中提到的,“唯一需要的属性是比较相等的对象具有相同的哈希值”。这是为了确保您的 Card 类可以作为可散列集合中的项目按预期工作。所以,重写__hash__ 方法是个好主意;也许,像这样:

    def __hash__(self):
        return hash((self.suit, self.rank))
    

    【讨论】:

      【解决方案4】:

      我正在做一些代码审查来帮助你开始使用 python,我去掉了你的 cmets(不说什么,顺便说一下为什么),并添加了我自己的。

      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
      

      【讨论】:

        猜你喜欢
        • 2012-04-03
        • 2020-11-07
        • 2021-08-03
        • 2020-04-17
        • 1970-01-01
        • 1970-01-01
        • 2021-05-13
        • 2011-03-15
        相关资源
        最近更新 更多