2015-11-20 42 views
1

幾本書(或教程)定義了一個卡,並以下列方式甲板:「類」與「namedtuple」模擬甲板在Python

import random 

class Card(object): 
    """ A card object with a suit and rank.""" 

    RANKS = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) 

    SUITS = ('Spades', 'Diamonds', 'Hearts', 'Clubs') 

    def __init__(self, rank, suit): 
     """Creates a card with the given rank and suit.""" 
     self.rank = rank 
     self.suit = suit 

    def __str__(self): 
     """Returns the string representation of a card.""" 
     if self.rank == 1: 
      rank = 'Ace' 
     elif self.rank == 11: 
      rank = 'Jack' 
     elif self.rank == 12: 
      rank = 'Queen' 
     elif self.rank == 13: 
      rank = 'King' 
     else: 
      rank = self.rank 
     return str(rank) + ' of ' + self.suit 

import random 

class Deck(object): 
    """ A deck containing 52 cards.""" 

    def __init__(self): 
     """Creates a full deck of cards.""" 
     self._cards = [] 
     for suit in Card.SUITS: 
      for rank in Card.RANKS: 
       c = Card(rank, suit) 
       self._cards.append(c) 

    def shuffle(self): 
     """Shuffles the cards.""" 
     random.shuffle(self._cards) 

    def deal(self): 
     """Removes and returns the top card or None 
     if the deck is empty.""" 
     if len(self) == 0: 
      return None 
     else: 
      return self._cards.pop(0) 

    def __len__(self): 
     """Returns the number of cards left in the deck.""" 
     return len(self._cards) 

    def __str__(self): 
     """Returns the string representation of a deck.""" 
     result = '' 
     for c in self._cards: 
      result = self.result + str(c) + '\n' 
     return result 

最近有一本書我讀它定義爲:

import collections 

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] 

如果沒有別的,這個版本「似乎」不那麼冗長。 (但這不是我關心的問題,因爲它們是比較代碼長度是錯誤的)。

對於這個例子,也許一般來說,定義卡的優缺點是什麼作爲名稱與班級?

如果答案只是一個是可變的而另一個不是,我有什麼理由關心它?

其中一個版本比另一個版本更噁心嗎?

+0

'namedtuple'具有不可變的實例,可能不包含任何用戶定義的函數。一個類可能不是不可變的(至少不是非常不可變的),你可以把它放在一堆有用的函數中。 – khelwood

回答

2

命名的元組真的只是不那麼冗長,因爲你不需要該類具有的樣板文件__init__

好的,所以你展示的實現也沒有很長的__str__函數,但是它的表示形式再次沒有類型所要求的特性,所以比較碼。

兩者之間的重要區別在於namedtuple爲您提供了不可變的對象,而上面顯示的類是可變的(並且需要額外的代碼才能使其不可變)。

額外的功能(如khelwood在註解中提到的),例如可以通過結合處理兩種:

class Card(collections.namedtuple('CardBase', ['rank', 'suit'])): 
    def __str__(self): 
     # code to say "Ace of spades" goes here 

結果仍具有隻讀.rank.suit屬性,雖然它現在有自己的字典爲其他可變屬性,所以它不再是一個不可變的類型。如果你是意圖混合只讀與讀寫屬性,那麼你可能比使用namedtuple更好使用@property,但如果你只是想將一些便利功能附加在某種非常適合namedtuple的東西上,那麼這工作。

使用namedtuple的最後一個可能的缺點是結果是一個元組。也就是說,可以使用[0][1]進行訪問,可以使用+將卡片對象添加在一起,結果無意義,其他元組都可以使用。對你的對象進行無意義/不相關的操作通常不會產生任何有害的影響,但它不是很好,因爲它可能會使自動生成的文檔膨脹,難以找到錯誤以及其他這樣的煩惱。改變已發佈的界面也很困難,因爲一旦你發佈它,有人可能會使用它。

+1

儘管在類定義中不說'__slots __ =()',你會失去'namedtuple'的一些優點。 – ppperry

+0

@ppperry:好的一點,對我來說,添加這些內容要比說我所說的不再是不可改變的更容易! –

+0

除了丟失\ _ \ _ slots \ _ \ _之外,您將失去繼承元組的所有功能。使用''rank,suit = card''解包裝; hashability for:''somedict [card] = value'',用''card1