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

Tip

Avoid clone methods

A clone method that unnecessarily duplicates an object is rarely needed in Python. Using cloning may be an indication of failure to understand the object-oriented design principles available in Python.

A clone method encapsulates the knowledge of object creation in the wrong place. The source object that's being cloned cannot know about the structure of the target object that was built from the clone. However, the reverse (targets having knowledge about a source) is acceptable if the source provides a reasonably well-encapsulated interface.

The examples we have shown here are effectively cloning because they're so simple. We'll expand on them in the next chapter. However, to show ways in which these fundamental techniques are used to do more than trivial cloning, we'll look at turning a mutable Hand object into a frozen, immutable Hand object.

The following is an example of a Hand object that can be built in either of the two ways:

class Hand3:
    def __init__( self, *args, **kw ):
        if len(args) == 1 and isinstance(args[0],Hand3):
            # Clone an existing hand; often a bad idea
            other= args[0]
            self.dealer_card= other.dealer_card
            self.cards= other.cards
        else:
            # Build a fresh, new hand.
            dealer_card, *cards = args
            self.dealer_card=  dealer_card
            self.cards= list(cards)

In the first case, a Hand3 instance has been built from an existing Hand3 object. In the second case, a Hand3 object has been built from individual Card instances.

This parallels the way a frozenset object can be built from individual items or an existing set object. We look more at creating immutable objects in the next chapter. Creating a new Hand from an existing Hand allows us to create a memento of a Hand object using a construct like the following code snippet:

h = Hand( deck.pop(), deck.pop(), deck.pop() )
memento= Hand( h )

We saved the Hand object in the memento variable. This can be used to compare the final with the original hand that was dealt, or we can freeze it for use in a set or mapping too.