Next / Previous / Contents / Shipman's homepage

5. The Singleton base class: A classic design pattern

The movement to codify standard design patterns in software architecture stems from this seminal work:

Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design patterns. Addison-Wesley, 1995, ISBN 0-201-63361-2.

The purpose of the Singleton design pattern is to make sure that a class has only instance. The Log object described in Section 3, “The singleton Log object” is an application of this pattern.

We provide here a base class called Singleton. When you write a class that inherits from this base class, the behavior of the class changes in one important respect: no matter how many times the constructor is called, there will be only one instance of the class.

If you want to write a class C that has this behavior, follow this procedure.

How to write a singleton class

  1. Download the code for the singleton.py module; see Section 2, “Files available online”.

  2. Import the module like this:

    import singleton
    
  3. Write the class declaration so it inherits the base class:

    class C(singleton.Singleton):
        ...
    
  4. Declare a class variable that is initially False. This variable will keep track of whether the constructor has ever been called. For example:

    class C(singleton.Singleton):
        ...
        INITIALIZED = False
    
  5. Keep in mind that although only one instance will ever exist, the constructor may be called many times. You must decide what to do on the second and successive calls.

    • If the constructor takes no arguments, you may want to simply return if this is not the first time the constructor has been called. Use the class variable (INITIALIZED in the example) to record whether the constructor has been called. See the discussion below.

    • If the constructor takes arguments, decide what to do when the constructor call is not the first.

      For example, consider a singleton that logs messages from a number of different points in the code. You might allow the user to pass an optional output stream argument, in order to request that log messages be sent to that stream. Or you may just decide to ignore any arguments after the first time.

So let us consider the case where you ignore constructor arguments after the first call. The outline for your class would look something like this:

class C(singleton.Singleton):
    ...
    INITIALIZED = False

    def __init__(self, *p, *kw):
        if C.INITIALIZED:
            return
        else:
            C.INITIALIZED = True

        # Process the arguments
        ...