This will be the easiest of all creational patterns. The concept is to create an instance of a class only once (regardless of how many times we call the class) and use that instance whenever we want. Let’s implement is fast on Python —
class SingletonMeta(type): _instance = None def __call__(self): if self._instance is None: self._instance = super().__call__() return self._instance class Singleton(metaclass=SingletonMeta): # Now implement your singleton class def some_business_logic(self): pass if __name__ == "__main__": s1 = Singleton() s2 = Singleton() # You can check they are both same instance assert(id(s1) == id(s2))
This is so easy! We made a metaclass
SingletonMeta and then use that to build our class
Singleton . Ok, now the question may arise "What is a metaclass?". The answer is really simple, "Metaclasses are the 'stuff' that creates classes". In Python, everything is object, right? So metaclasses are the classes that are used to create these objects. Here is an elaborate answer about metaclass.
In our case, our
SingletonMeta class is the creator of our
Singleton class. And in this metaclass, we can define custom logic on how a class should behave or what it will be its property. In
SingletonMeta class, we took an
_instance and every time the class get
__call__ to initiate itself, it tries to find the
_instance , if not yet instantiated, creates the instance of the class and save it to
_instance. So in the runtime, when it gets called again, it supplies the same instance.
Now the question may arise "Why would we need such a pattern?". Well, the easiest example can be a REST/RPC client. In web applications, we need to call other services/API's. So we make a client that normally does the communication and returns the result to us. This client can be used in several places in the same application, do we really need to make this same instance every time, to make a call? Here we can use the singleton. Also, the DB client, are we creating the client every time when we need some data from DB? Rather make a client when the application starts and use that connection to call DB. In case of concurrency, DB calls may use a connection pool to support parallel communication, but that's a very different topic for now.
Hope this helps you :)