Deck

Main module of the package, it contains the Card and French Deck inspired by the Fluent Python book

Card

The Fluent Python card representation was kept. The namedtuple usage allows a simple and Pythonic representation

Card = collections.namedtuple("Card", ["rank", "suit"])
diamon_7 = Card("7", "diamonds")
diamon_7
Card(rank='7', suit='diamonds')

French Deck

French Deck is the most well popular deck in card games, it contains 52 cards splitted between 4 suits (spades, hearts, diamonds, clubs).

The FrenchDeck class uses dunder methods to define a pythonic interface.

All ranks of this French Deck implementation uses a integer number, this means that the A card corresponds to the number 1, and J, Q, K to 11, 12, 13, respectively. This will help applications like blackjack games to count the values in a player hand.

Code
class FrenchDeck:
    ranks = [n for n in range(1, 14)]
    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]

    def __iter__(self) -> Iterator[Card]:
        return iter(self.cards)

    def __repr__(self):
        return "\n".join(str(card) for card in self.cards)

source

FrenchDeck

 FrenchDeck ()

Initialize self. See help(type(self)) for accurate signature.

The __iter__ dunder method is not necessary because __getitem__ already makes the FrenchDeck iterable but [MyPy doesn’t recognize a class iterable when it implements only __getitem__]

deck = FrenchDeck()

The pythonic interface allows the usage of features from the Python built-in system like random.choice and slicing the deck

random.choice(deck)
Card(rank=1, suit='diamonds')
deck[:2]
[Card(rank=1, suit='spades'), Card(rank=2, suit='spades')]

Syntactic sugar

Due to the Pythonic interface of French Deck the following function could be easily developed by its users, but to improve readability some syntactic sugar was added to the shuffle and draw cards operations


source

FrenchDeck.shuffle

 FrenchDeck.shuffle ()

Shuffles all cards available


source

FrenchDeck.draw

 FrenchDeck.draw ()

Removes a card from the top of the deck

card = deck.draw()  # type: ignore
card
Card(rank=13, suit='hearts')

source

FrenchDeck.draw_n

 FrenchDeck.draw_n (n_cards:int)

Removes n cards from the top of the deck

Type Details
n_cards int
Returns typing.List[main.Card] number of cards to draw
cards = deck.draw_n(10)  # type: ignore
cards
[Card(rank=12, suit='hearts'),
 Card(rank=11, suit='hearts'),
 Card(rank=10, suit='hearts'),
 Card(rank=9, suit='hearts'),
 Card(rank=8, suit='hearts'),
 Card(rank=7, suit='hearts'),
 Card(rank=6, suit='hearts'),
 Card(rank=5, suit='hearts'),
 Card(rank=4, suit='hearts'),
 Card(rank=3, suit='hearts')]