2011-06-02 42 views
16

這是我第一次在堆棧溢出,所以我很抱歉,如果格式不適合與網站相當正確。 我剛剛開始學習編程,接近2個星期過去了。我正在學習從http://openbookproject.net/thinkcs/python/english3e/index.html蟒蛇和一切都相當不錯,直到現在,我剛卡住了幾個小時。 我googled了很多,但無法找到一個妥善的解決方案,我的問題,所以我在這裏。Python:'列表中的對象'檢查和'__cmp__'溢出

我試圖讓CHM中解釋的OldMaidGame()運行沒有問題。 - 大部分代碼也來自上一章。

我發現我無法得到Deck.remove,Hand.remove_matches或任何其他類型的刪除功能的工作。經過一些調試後,我發現 當程序檢查卡片是否存在於甲板/手/等位置時發生問題。它永遠無法匹配。然後,在回顧一下 這一章後(在第16章),我發現'如果卡片/甲板/手/等等:移除(卡片)'等等。 cmp()確定卡片是否實際存在於甲板/手/等。這是我對cmp的版本,在給電子書給定的代碼添加'ace'之後。

def __cmp__(self, other): 
    """ Compares cards, returns 1 if greater, -1 if lesser, 0 if equal """ 
    # check the suits 
    if self.suit > other.suit: return 1 
    if self.suit < other.suit: return -1 
    # suits are the same... check ranks 
    # check for aces first. 
    if self.rank == 1 and other.rank == 1: return 0 
    if self.rank == 1 and other.rank != 1: return 1 
    if self.rank != 1 and other.rank == 1: return -1 
    # check for non-aces. 
    if self.rank > other.rank: return 1 
    if self.rank < other.rank: return -1 
    # ranks are the same... it's a tie 
    return 0 

CMP本身似乎罰款據我所知,OFC我可以使用一些技巧如何使它更好的(像ACE檢查)。 所以我不知道爲什麼在卡片/手牌檢查卡總是返回false。 這是給定的刪除功能:

class Deck: 
    ... 
    def remove(self, card): 
     if card in self.cards: 
      self.cards.remove(card) 
      return True 
     else: 
      return False 

拼命試圖得到它的工作,我想出了這個:

class Deck: 
    ... 
    def remove(self, card): 
     """ Removes the card from the deck, returns true if successful """ 
     for lol in self.cards: 
      if lol.__cmp__(card) == 0: 
       self.cards.remove(lol) 
       return True 
     return False 

似乎正常工作,直到我轉移到了其他非工作刪除功能:

class OldMaidHand(Hand): 
    def remove_matches(self): 
     count = 0 
     original_cards = self.cards[:] 
     for card in original_cards: 
      match = Card(3 - card.suit, card.rank) 
      if match in self.cards: 
       self.cards.remove(card) 
       self.cards.remove(match) 
       print("Hand {0}: {1} matches {2}".format(self.name, card, match)) 
       count = count + 1 
     return count 

我又做了一些調整:

class OldMaidHand(Hand): 
    def remove_matches(self): 
     count = 0 
     original_cards = self.cards[:] 
     for card in original_cards: 
      match = Card(3 - card.suit, card.rank) 
      for lol in self.cards: 
       if lol.__cmp__(match) == 0: 
        self.cards.remove(card) 
        self.cards.remove(match) 
        print("Hand {0}: {1} matches {2}".format(self.name, card, match)) 
        count = count + 1 
     return count 

該卡的移除工作正常,但它會給我一個錯誤(x不在列表),當我試圖刪除匹配。另外一個我們可能也可以做這個工作,但是因爲它已經感覺我走錯了路,因爲我無法修正原來的'卡在甲板/手/等'等,我來到這裏尋找一些答案/提示。

感謝您的閱讀,我非常感謝任何幫助,您可以給:)

--------------------- EDIT 1 *>

這是我當前的代碼: http://pastebin.com/g77Y4Tjr

--------------------- EDIT 2 *>

我試着每一個cmp在這裏建議,我仍然無法找到它與'進'卡。

>>> a = Card(0, 5) 
>>> b = Card(0, 1) 
>>> c = Card(3, 1) 
>>> hand = Hand('Baris') 
>>> hand.add(a) 
>>> hand.add(b) 
>>> hand.add(c) 
>>> d = Card(3, 1) 
>>> print(hand) 
Hand Baris contains 
5 of Clubs 
Ace of Clubs 
    Ace of Spades 
>>> d in hand.cards 
False 
>>> 

我也試過card.py @DSM已成功使用,我得到的錯誤有太多,像在排序功能它說,它不能比較兩個卡對象。
所以我想知道,也許這是一個Python 3.2的問題,或者語法在某處改變了?

+4

+1決定學習Python! – 2011-06-02 13:59:23

+0

你確定卡組裏實際上有卡嗎? – 2011-06-02 14:04:46

+1

@ Space_C0wb0y是的,其他一切正常。沒有發佈整個程序,因爲我不確定這個網站是否合適,因爲它可以在我鏈接的電子書上找到。唯一不合格的是'in'檢查。即使我只是手動創建一個空的甲板/手牌,添加1-2張牌,並嘗試檢查程序是否識別它們中的任何一個,它都會失敗。 – Ulquiomaru 2011-06-02 14:11:38

回答

6

「所以我想,也許這是與Python 3.2的一個問題,也許語法已經改變的地方?」

哦,你正在運行Python 3.2? 這絕不會在Python 3中工作:python 3不使用__cmp__

查看data model (look for __eq__)。還有一些其他的東西what's new in Python 3方式太容易錯過了。

對不起,這是我們這裏的Python程序員;我們應該早點抓住這一點。大多數人可能會看到所有的代碼,甚至沒有想到它的源代碼顯然是Python 2代碼,並認爲這就是我們正在處理的內容。在Python 3.2中甚至不存在cmp函數,但是它不會因爲NameError而炸燬的原因是因爲__cmp__永遠不會被調用。

如果我運行在Python 3.2的代碼,我精確地再現您的問題:

>>> c = Card(0,2) 
>>> str(c) 
'2 of Clubs' 
>>> c in [c] 
True 
>>> c in Deck().cards 
False 

在Python 3,你要麼實現所有的有錢CMPS或__eq__和他們中的一個,並使用total_ordering裝飾。

from functools import total_ordering 

@total_ordering 
class Card(object): 
    """Represents a standard playing card.""" 
    suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"] 
    rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7", 
       "8", "9", "10", "Jack", "Queen", "King"] 
    def __init__(self, suit=0, rank=2): 
     self.suit = suit 
     self.rank = rank 
    def __str__(self): 
     return '%s of %s' % (Card.rank_names[self.rank], 
          Card.suit_names[self.suit]) 
    def __repr__(self): return str(self) 
    def __lt__(self, other): 
     t1 = self.suit, self.rank 
     t2 = other.suit, other.rank 
     return t1 < t2 
    def __eq__(self, other): 
     t1 = self.suit, self.rank 
     t2 = other.suit, other.rank 
     return t1 == t2 


>>> c = Card(2,3) 
>>> c 
3 of Hearts 
>>> c in Deck().cards 
True 
0

我似乎無法重現與無法通過Deck.remove刪除卡的問題。如果我與card.py開始在the thinkpython site,並添加您已經發布了有remove函數,它似乎工作:

>>> deck = Deck() 
>>> str(deck).split('\n') 
['Ace of Clubs', '2 of Clubs', '3 of Clubs', '4 of Clubs', '5 of Clubs', '6 of Clubs', '7 of Clubs', '8 of Clubs', '9 of Clubs', '10 of Clubs', 'Jack of Clubs', 'Queen of Clubs', 'King of Clubs', 'Ace of Diamonds', '2 of Diamonds', '3 of Diamonds', '4 of Diamonds', '5 of Diamonds', '6 of Diamonds', '7 of Diamonds', '8 of Diamonds', '9 of Diamonds', '10 of Diamonds', 'Jack of Diamonds', 'Queen of Diamonds', 'King of Diamonds', 'Ace of Hearts', '2 of Hearts', '3 of Hearts', '4 of Hearts', '5 of Hearts', '6 of Hearts', '7 of Hearts', '8 of Hearts', '9 of Hearts', '10 of Hearts', 'Jack of Hearts', 'Queen of Hearts', 'King of Hearts', 'Ace of Spades', '2 of Spades', '3 of Spades', '4 of Spades', '5 of Spades', '6 of Spades', '7 of Spades', '8 of Spades', '9 of Spades', '10 of Spades', 'Jack of Spades', 'Queen of Spades', 'King of Spades'] 
>>> len(deck.cards) 
52 
>>> c = Card(suit=0, rank=8) 
>>> str(c) 
'8 of Clubs' 
>>> c in deck.cards 
True 
>>> deck.remove(c) 
True 
>>> len(deck.cards) 
51 
>>> c in deck.cards 
False 
>>> str(deck).split('\n') 
['Ace of Clubs', '2 of Clubs', '3 of Clubs', '4 of Clubs', '5 of Clubs', '6 of Clubs', '7 of Clubs', '9 of Clubs', '10 of Clubs', 'Jack of Clubs', 'Queen of Clubs', 'King of Clubs', 'Ace of Diamonds', '2 of Diamonds', '3 of Diamonds', '4 of Diamonds', '5 of Diamonds', '6 of Diamonds', '7 of Diamonds', '8 of Diamonds', '9 of Diamonds', '10 of Diamonds', 'Jack of Diamonds', 'Queen of Diamonds', 'King of Diamonds', 'Ace of Hearts', '2 of Hearts', '3 of Hearts', '4 of Hearts', '5 of Hearts', '6 of Hearts', '7 of Hearts', '8 of Hearts', '9 of Hearts', '10 of Hearts', 'Jack of Hearts', 'Queen of Hearts', 'King of Hearts', 'Ace of Spades', '2 of Spades', '3 of Spades', '4 of Spades', '5 of Spades', '6 of Spades', '7 of Spades', '8 of Spades', '9 of Spades', '10 of Spades', 'Jack of Spades', 'Queen of Spades', 'King of Spades'] 

看來,如果我通過你更換__cmp__工作,太:

>>> deck = Deck() 
>>> c = Card(suit=0,rank=1) 
>>> c in deck.cards 
True 
>>> deck.remove(c) 
True 
>>> len(deck.cards) 
51 

所以,一定要有所不同。你可以轉儲你的整個代碼 - 和一些展示bug的代碼 - 在某處(pastebin,gist等)?


(FWIW,我的王牌過王CMP看起來是這樣的:

def __cmp__(self, other): 
    def aceshigh(r): return 14 if r==1 else r 
    t1 = self.suit, aceshigh(self.rank) 
    t2 = other.suit, aceshigh(other.rank) 
    return cmp(t1, t2) 

練習:刪除幻數。)

+0

該網站上的card.py也不適用於我。我不是在討論像打印語法這樣的python版本之間的小東西,即使sort函數也會產生錯誤。奇怪的。我只有2周齡的Python用戶,這是殺我:( – Ulquiomaru 2011-06-02 21:17:55

1

我也無法重現錯誤。這對我來說可以。我唯一的建議是,當你迭代它時,你可能不應該修改列表(即,通過self.cards在循環內調用self.cards.remove)。這無法解釋爲什麼使用「in」的版本不適合你。

你CMP函數可以寫成某種程度上更簡潔(恕我直言更簡單)爲:

def __cmp__(self, other): 
    """ Compares cards, returns 1 if greater, -1 if lesser, 0 if equal """ 
    return cmp((self.suit, self.rank == 1, self.rank), 
       (other.suit, other.rank == 1, other.rank)) 

或者如果你喜歡:

return (cmp(self.suit, other.suit) or 
      cmp(self.rank == 1, other.rank == 1) or 
      cmp(self.rank, other.rank)) 
0

這聽起來像你有一個問題你的甲板變量。或者remove函數指向一個帶有空白卡片的不同對象,否則你有一個命名空間問題。甲板對象的刪除功能是否是部分?

我建議添加一些打印甲板線。一個剛剛初始化後,看看它裏面有什麼,一個就像你調用remove一樣。

0

正如其他人指出的那樣,您的比較功能應該可以工作,需要更多的細節來弄清楚發生了什麼。至於建議:

  1. Stick Ace在行列末尾,使用0-12來映射行列。這似乎是對我來說很自然的方法。標準庫的

  2. 利用:

    A.使用random.shuffle洗牌。用cmp來處理比較。

    C. collections.defaultdict在我看來,這使得清潔remove_matches方法。

  3. 建議的__str__方法真的很煩人。

  4. 實施__repr__

替代實現:

from collections import defaultdict 
import random 

class Card(object): 
    suits = ["Clubs", "Diamonds", "Hearts", "Spades"] 
    ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"] 

    def __init__(self, suit=0, rank=0): 
     self.suit = suit 
     self.rank = rank 

    def __str__(self): 
     return self.ranks[self.rank] + " of " + self.suits[self.suit] 

    def __repr__(self): 
     return self.__str__() 

    def __cmp__(self, other): 
     return cmp((self.suit, self.rank), (other.suit, other.rank)) 

class Deck(object): 
    def __init__(self): 
     self.cards = [] 
     for suit in range(4): 
      for rank in range(13): 
       self.cards.append(Card(suit=suit, rank=rank)) 

    def shuffle(self): 
     random.shuffle(self.cards) 

    def remove(self, card): 
     if card in self.cards: 
      self.cards.remove(card) 

    def pop(self): 
     return self.cards.pop() 

    def is_empty(self): 
     if len(self.cards) is 0: 
      return True 
     return False 

    def deal(self, hands, num_cards=999): 
     num_hands = len(hands) 
     for i in range(num_cards): 
      if self.is_empty(): break # break if out of cards 
      card = self.pop()   # take the top card 
      hand = hands[i % num_hands] # whose turn is next? 
      hand.add(card)    # add the card to the hand 

class Hand(Deck): 
    def __init__(self, name=""): 
     self.cards = [] 
     self.name = name 

    def add(self,card): 
     self.cards.append(card) 

class OldMaidHand(Hand): 
    def remove_matches(self): 
     matches = defaultdict(list) 
     for card in self.cards: 
      matches[card.rank].append(card) 
     for cards in matches.values(): 
      if len(cards) == 2: 
       print("Hand {0}: {1} matches {2}".format(self.name, *cards)) 
       for card in cards: 
        self.remove(card)