Complex composite objects

The following is an example of a Blackjack Hand description that might be suitable for emulating play strategies:

class Hand:

def __init__(self, dealer_card: Card) -> None:
self.dealer_card: Card = dealer_card
self.cards: List[Card] = []

def hard_total(self) -> int:
return sum(c.hard for c in self.cards)

def soft_total(self) -> int:
return sum(c.soft for c in self.cards)

def __repr__(self) -> str:
return f"{self.__class__.__name__} {self.dealer_card} {self.cards}"

In this example, we have a self.dealer_card instance variable based on a parameter of the __init__() method. The self.cards instance variable, however, is not based on any parameter. This kind of initialization creates an empty collection. Note that the assignment to the self.cards variable requires a type hint to inform mypy of the expected contents of the self.cards collection.

To create an instance of Hand, we can use the following code:

>>> d = Deck()
>>> h = Hand(d.pop())
>>> h.cards.append(d.pop())
>>> h.cards.append(d.pop())

This has the disadvantage of consisting of a long-winded sequence of statements to build an instance of a Hand object. It can become difficult to serialize the Hand object and rebuild it with an initialization as complex as this. Even if we were to create an explicit append() method in this class, it would still take multiple steps to initialize the collection.

The definition of the __repr__() method illustrates this problem. We can't provide a simple string representation that would rebuild the object. The typical use of __repr__() is to create a Pythonic view of the object's state, but, with such a complex initialization, there's no simple expression to represent it.

We could try to create a fluent interface, but that wouldn't really simplify things; it would merely mean a change in the syntax of the way that a Hand object is built. A fluent interface still leads to multiple method evaluations. When we take a look at the serialization of objects in part 2, Persistence and Serialization, we'd like an interface that's a single class-level function; ideally the class constructor. We'll look at this in depth in Chapter 10, Serializing and Saving – JSON, YAML, Pickle, CSV, and XML.

You should also note that the hard total and soft total method functions shown here don't fully follow the rules of Blackjack. We'll return to this issue in Chapter 3, Integrating Seamlessly – Basic Special Methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset