Mastering Objectoriented Python
上QQ阅读APP看书,第一时间看更新

More complex initialization alternatives

In order to write a multi-strategy initialization, we're often forced to give up on specific named parameters. This design has the advantage that it is flexible, but the disadvantage that it has opaque, meaningless parameter names. It requires a great deal of documentation explaining the variant use cases.

We can expand our initialization to also split a Hand object. The result of splitting a Hand object is simply another constructor. The following code snippet shows how the splitting of a Hand object might look:

class Hand4:
    def __init__( self, *args, **kw ):
        if len(args) == 1 and isinstance(args[0],Hand4):
            # Clone an existing handl often a bad idea
            other= args[0]
            self.dealer_card= other.dealer_card
            self.cards= other.cards
        elif len(args) == 2 and isinstance(args[0],Hand4) and 'split' in kw:
            # Split an existing hand
            other, card= args
            self.dealer_card= other.dealer_card
            self.cards= [other.cards[kw['split']], card]
        elif len(args) == 3:
            # Build a fresh, new hand.
            dealer_card, *cards = args
            self.dealer_card=  dealer_card
            self.cards= list(cards)
        else:
            raise TypeError( "Invalid constructor args={0!r} kw={1!r}".format(args, kw) )
    def __str__( self ):
        return ", ".join( map(str, self.cards) )

This design involves getting extra cards to build proper, split hands. When we create one Hand4 object from another Hand4 object, we provide a split keyword argument that uses the index of the Card class from the original Hand4 object.

The following code snippet shows how we'd use this to split a hand:

d = Deck()
h = Hand4( d.pop(), d.pop(), d.pop() )
s1 = Hand4( h, d.pop(), split=0 )
s2 = Hand4( h, d.pop(), split=1 )

We created an initial h instance of Hand4 and split it into two other Hand4 instances, s1 and s2, and dealt an additional Card class into each. The rules of blackjack only allow this when the initial hand has two cards of equal rank.

While this __init__() method is rather complex, it has the advantage that it can parallel the way in which fronzenset is created from an existing set. The disadvantage is that it needs a large docstring to explain all these variations.