A Pythonic Card Deck
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, positon):
return self._cards[positon]
namedtuple
can be used to build classes of objects that are just bundle of attributes with no custom methods, like a database record.
>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')
KBecause our __getitem__
delegates to the []
operator of self._cards, our deck automatically supports slicing.
>>> deck = FrenchDeck()
>>> len(deck)
52
>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
Iteration:
>>> for card in deck:
... print(card)
Card(rank='2', suit='spades') Card(rank='3', suit='spades') Card(rank='4', suit='spades')
If a collection has no contains method, the in
operator does a sequential scan.
>>> Card('Q', 'hearts') in deck
True
Sorting
suit_values = dict(spades=3, heart=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
>>> for card in sorted(deck, key=spades_high):
... print(card)
The first thing to know about special methods is that they are meant to be called by the Python interpreter, and not by you. You don't write my_object.__len__()
. You write len(my_object)
Several special methods allow user objects to respond to operators such as +.