Object Oriented Playing Cards in Python

June 13, 2019

enum became a part of the Python standard library starting in version 3.4 and I thought that the classic OOP playing cards example would be a good demonstration of it.

In this example, I'm not going to worry about the actual playing card values like in Poker (twos are more valuable than threes, spades are more valuable than hearts, etc.) since there are many games where cards may not conform to those values.

I'll first create the set of four enums for the suite and the set of thirteen enums for the card's face value. I'll also use auto, since I'm not going to worry about the exact value of the enum, though I'll list them in Poker value order and auto will automatically give me those values anyway.

from enum import Enum, auto

class Suite(Enum):
    DIAMOND = auto()
    CLUB = auto()
    HEART = auto()
    SPADE = auto()

class Value(Enum):
    TWO = auto()
    THREE = auto()
    FOUR = auto()
    FIVE = auto()
    SIX = auto()
    SEVEN = auto()
    EIGHT = auto()
    NINE = auto()
    TEN = auto()
    JACK = auto()
    QUEEN = auto()
    KING = auto()
    ACE = auto()

Now I'll create the Card class with getters and setters so I can ensure the proper enums are passed when initializing each card.

class Card:
    def __init__(self, suite: Suite, value: Value):
        self.suite = suite
        self.value = value

    def suite(self):
        return self._suite

    def value(self):
        return self._value

    def suite(self, suite: Suite):
        if suite not in Suite:
            raise Exception
        self._suite = suite

    def value(self, value: Value):
        if value not in Value:
            raise Exception
        self._value = value

    def __repr__(self):
        return f"<Card {self.value} of {self.suite}>"

If we try to initialize the Card with anything other than a valid Suite or Value, Python will raise an Exception.

Okay, now we can create a class for a deck of cards.

class Deck:
    def __init__(self):
        self.cards = [Card(s, v) for s in Suite for v in Value]

    def __repr__(self):
        output = [f"{c}\n" for c in self.cards]
        return "".join(output)

Now, let's give this a try and see if everything is alright.

>>> from card import Suite, Value, Card, Deck
>>> deck = Deck()
>>> len(deck.cards)
>>> deck
<Card Value.TWO of Suite.DIAMOND>
<Card Value.THREE of Suite.DIAMOND>
<Card Value.FOUR of Suite.DIAMOND>
<Card Value.FIVE of Suite.DIAMOND>
<Card Value.SIX of Suite.DIAMOND>
<Card Value.SEVEN of Suite.DIAMOND>
<Card Value.EIGHT of Suite.DIAMOND>
<Card Value.NINE of Suite.DIAMOND>
<Card Value.TEN of Suite.DIAMOND>
<Card Value.JACK of Suite.DIAMOND>
<Card Value.QUEEN of Suite.DIAMOND>
<Card Value.KING of Suite.DIAMOND>
<Card Value.ACE of Suite.DIAMOND>
<Card Value.TWO of Suite.CLUB>
<Card Value.THREE of Suite.CLUB>
<Card Value.FOUR of Suite.CLUB>
<Card Value.FIVE of Suite.CLUB>
<Card Value.SIX of Suite.CLUB>
<Card Value.SEVEN of Suite.CLUB>
<Card Value.EIGHT of Suite.CLUB>
<Card Value.NINE of Suite.CLUB>
<Card Value.TEN of Suite.CLUB>
<Card Value.JACK of Suite.CLUB>
<Card Value.QUEEN of Suite.CLUB>
<Card Value.KING of Suite.CLUB>
<Card Value.ACE of Suite.CLUB>
<Card Value.TWO of Suite.HEART>
<Card Value.THREE of Suite.HEART>
<Card Value.FOUR of Suite.HEART>
<Card Value.FIVE of Suite.HEART>
<Card Value.SIX of Suite.HEART>
<Card Value.SEVEN of Suite.HEART>
<Card Value.EIGHT of Suite.HEART>
<Card Value.NINE of Suite.HEART>
<Card Value.TEN of Suite.HEART>
<Card Value.JACK of Suite.HEART>
<Card Value.QUEEN of Suite.HEART>
<Card Value.KING of Suite.HEART>
<Card Value.ACE of Suite.HEART>
<Card Value.TWO of Suite.SPADE>
<Card Value.THREE of Suite.SPADE>
<Card Value.FOUR of Suite.SPADE>
<Card Value.FIVE of Suite.SPADE>
<Card Value.SIX of Suite.SPADE>
<Card Value.SEVEN of Suite.SPADE>
<Card Value.EIGHT of Suite.SPADE>
<Card Value.NINE of Suite.SPADE>
<Card Value.TEN of Suite.SPADE>
<Card Value.JACK of Suite.SPADE>
<Card Value.QUEEN of Suite.SPADE>
<Card Value.KING of Suite.SPADE>
<Card Value.ACE of Suite.SPADE>


I'd like to send you a weekly recap of all the articles I write as well as my take on the latest news on web development with Vue, React, Elixir/Phoenix, and others. Just fill out your email and name below!

Prev: Structure a Flask React Monorepo
Next: Python Web Frameworks: A Survey