HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Singleton Decorator

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
decoratorsingletonstackoverflow

Problem

I've written a class that makes writing singletons easy. The class is meant to be used as a decorator (example below). I'd like to see your thoughts about the code, the documentation, and everything else that you feel is worth noting.

class Singleton:
    """
    Helper class meant to ease the creation of singletons. This
    should be used as a decorator -- not a metaclass -- to the class
    that should be a singleton.

    The decorated class should define only one `__init__` function
    that takes only the `self` argument. Other than that, there are
    no restrictions that apply to the decorated class.

    To get the singleton instance, use the `Instance` method. Trying
    to use `__call__` will result in a `SingletonError` being raised.

    """

    _singletons = dict()

    def __init__(self, decorated):
        self._decorated = decorated

    def Instance(self):
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        key = self._decorated.__name__

        try:
            return Singleton._singletons[key]
        except KeyError:
            Singleton._singletons[key] = self._decorated()
            return Singleton._singletons[key]

    def __call__(self):
        """
        Call method that raises an exception in order to prevent creation
        of multiple instances of the singleton. The `Instance` method should
        be used instead.

        """
        raise SingletonError(
            'Singletons must be accessed through the `Instance` method.')

class SingletonError(Exception):
    pass


Now to test if the documentation was clear enough think about how you understood this class is meant to be used... Now look at this example and compare:

```
@Singleton
class Foo:
def __init__(self):
print('Foo created')

def bar(sel

Solution

It might be beneficial to add positional and keyword arguments to the __call__() method. That way you'll get your SingletonError for any call you attempt to make, rather than just the no-argument call.

You may want to add methods to delete or redefine singletons if necessary or restructure your class to address naming conflicts. It breaks if you define one singleton and use it, then later redefine a new singleton using the same name.

Consider making Instance a property rather than a method.

Consider using "new-style" class syntax explicitly.

Context

StackExchange Code Review Q#4648, answer score: 3

Revisions (0)

No revisions yet.