Search code examples
pythonclasssocketssingletoninstance

Single instance of class in Python


I am creating a Python application that includes socket communication with a server. I would like to have a module which can be used throughout my entire application (several other modules). Currently my module look like this:

class SocketCommunication:

    def __init__(self):
        self.socketIO = SocketIO(settings.ADDRESS, settings.PORT, Namespace)

    def emit(self, message, data):
        json_data = json.dumps(data.__dict__)
        self.socketIO.emit(message, json_data)


class Namespace(BaseNamespace):
    def on_connect(self):
        print '[Connected]'

    def on_disconnect(self):
        print "[Disconnected]"

When I use this in other modules I do the following:

import SocketCommunication
self.sc = SocketCommunication()

The problem is that every time I do this, a new connection is created which will be displayed as a new client on the server, and that is undesirable. From what I can read, Singletons should be avoided in Python and therefore I am curious about what is best practice for this type of problem?


Solution

  • The following are three ways to use singleton in Python. Using metaclass and decorator to reach the goal.

    1. use __new__

       class Singleton(object):
           def __new__(cls, *args, **kw):
               if not hasattr(cls, '_instance'):
                   orig = super(Singleton, cls)
                   cls._instance = orig.__new__(cls, *args, **kw)
               return cls._instance
      
       class MyClass(Singleton):
           a = 1
      
       one = MyClass()
       two = MyClass()
      
       two.a = 3
       print one.a
       #3
       print id(one)
       #29097904
       print id(two)
       #29097904
       print one == two
       #True
       print one is two
       #True
      
    2. use __metaclass__

    class Singleton2(type):
        def __init__(cls, name, bases, dict):
            super(Singleton2, cls).__init__(name, bases, dict)
            cls._instance = None
    
        def __call__(cls, *args, **kw):
            if cls._instance is None:
                cls._instance = super(Singleton2, cls).__call__(*args, **kw)
            return cls._instance
    
    
        class MyClass2(object):
            __metaclass__ = Singleton2
    
        one = MyClass2()
        two = MyClass2()
    
        two.a = 3
        print one.a
        #3
        print id(one)
        #31495472
        print id(two)
        #31495472
        print one == two
        #True
        print one is two
        #True
    
    1. use decorator

        def singleton(cls, *args, **kw):
           instances = {}
           def _singleton(*args, **kw):
              if cls not in instances:
                   instances[cls] = cls(*args, **kw)
              return instances[cls]
           return _singleton
      
       @singleton
       class MyClass3(object):
           a = 1
           def __init__(self, x=0):
               self.x = x
      
       one = MyClass3()
       two = MyClass3()
      
       two.a = 3
       print one.a
       #3
       print id(one)
       #29660784
       print id(two)
       #29660784
       print one == two
       #True
       print one is two
       #True
       one.x = 1
       print one.x
       #1
       print two.x
       #1
      

    I prefer to use decorator.