Context manager as a factory

We can create a context manager class, which is a factory for an application object. This gives us a pleasant separation of design considerations without cluttering up an application class with context management features.

Let's say we want a deterministic Deck for dealing in blackjack. This isn't as useful as it might sound. For unit testing, we'll need a completely mock deck with specific sequences of cards. This has the advantage that the context manager works with the classes we already saw.

We'll extend the simple context manager shown earlier to create a Deck that can be used within the with statement context.

The following is a class that is a factory for Deck and also tweaks the random module:

class Deterministic_Deck:
    def __init__( self, *args, **kw ):
        self.args= args
        self.kw= kw
    def __enter__( self ):
        self.was= random.getstate()
        random.seed( 0, version=1 )
        return Deck( *self.args, **self.kw )
    def __exit__( self, exc_type, exc_value, traceback ):
        random.setstate( self.was )

The preceding context manager class preserves the argument values so that it can create a Deck with the given arguments.

The __enter__() method preserves the old random number state and then sets the random module in a mode that provides a fixed sequence of values. This is used to build and shuffle the deck.

Note that the __enter__() method returns a newly minted Deck object to be used in the with statement context. This is assigned via the as clause in the with statement.

We could have provided similar functionality in another way. We could create an instance of random.Random(x=seed) within the Deck class. While that also works well, it tends to clutter the Deck class with code that's only used for demonstrations.

The following is a way to use this factory context manager:

with Deterministic_Deck( size=6 ) as deck:
    h = Hand( deck.pop(), deck.pop(), deck.pop() )

The preceding example of code guarantees a specific sequence of cards that we can use for demonstration purposes.