The Python Data Modal

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)

Special Methods

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)

Emulating Numeric Types

Several special methods allow user objects to respond to operators such as +.