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 ): self.dealer_card= dealer_card self.cards= [] def hard_total(self ): return sum(c.hard for c in self.cards) def soft_total(self ): return sum(c.soft for c in self.cards)
In this example, we have an instance variable self.dealer_card
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.
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 that a long-winded sequence of statements is used to build an instance of a Hand
object. It can become difficult to serialize the Hand
object and rebuild it with an initialization such as this one. Even if we were to create an explicit append()
method in this class, it would still take multiple steps to initialize the collection.
We could try to create a fluent interface, but that doesn't really simplify things; it's merely 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 9, Serializing and Saving - JSON, YAML, Pickle, CSV, and XML.
Note also that the hard total and soft total method functions shown here don't fully follow the rules of blackjack. We return to this issue in Chapter 2, Integrating Seamlessly with Python – Basic Special Methods.