1

I am new to Python and I am trying to learn this language by checking and creating examples of design patterns in Python.

I have a confusion with classic implementation of Singleton Pattern. Most of the articles out there mentions following implementation of Singleton as classic

class Singleton(object):
    name = None

    @staticmethod
    def instance():
        if '_instance' not in Singleton.__dict__:
            Singleton._instance = Singleton()

        return Singleton._instance


s1 = Singleton().instance();
s2 = Singleton().instance();

assert s1 is s2

But I am not fully convinced with this implementation because no where we are restricting users from creating multiple objects of Singleton class and I can still create an instance of this class by calling Singleton(). In Java, we prevent this by making constructor of class as Private.

Another implementation someone pointed me out is

class Singleton(object):
    _instances = {}

    def __new__(class, *args, **kwargs):
        if class not in class._instances:
            instance = super().__new__(class)
            class.__instances[class] = instance
        return class._instances[class]

And this has spinned my head off. Can someone explain me how this works?

Lokesh Agrawal
  • 3,269
  • 6
  • 28
  • 66
  • 1
    Override `__new__()` and always return the same instance. – kindall Sep 16 '18 at 06:04
  • Possible duplicate of [Creating a singleton in Python](https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python) – Stefan Papp Sep 16 '18 at 06:04
  • Thanks for pointing but this is not a duplicate. – Lokesh Agrawal Sep 16 '18 at 06:18
  • The singleton pattern isn't very "classic" in Python. There really is no need for it. – juanpa.arrivillaga Sep 16 '18 at 06:19
  • Then how do you create classes for logging etc that needs just one object? – Lokesh Agrawal Sep 16 '18 at 06:20
  • I would just use a module, which is essentially a singleton object that never requires instantiation. Or I would create a class and instantiate it once. Again, Python is not Java. There are different idiomatic ways of doing things. – juanpa.arrivillaga Sep 16 '18 at 06:20
  • 1
    In Python, if you just need one instance of something, you just create one instance. Simple! – kindall Sep 16 '18 at 06:22
  • @kindall yeah, if you are going to be using global mutable state, you might as well be explicit about it. – juanpa.arrivillaga Sep 16 '18 at 06:23
  • See the metaclass based implementation in [this question](https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python). I would say it is the correct way of creating a "Java-like singleton class". However, in Python, you would typically just have a module. The biggest difference between Java and Python is that Python doesn't force you to make everything a class definition. – juanpa.arrivillaga Sep 16 '18 at 06:31
  • >> In Python, if you just need one instance of something, you just create one instance. Simple! How are we enforcing? – Lokesh Agrawal Sep 16 '18 at 06:33
  • @LokeshAgrawal why would you need to enforce it? Only if you have horribly coupled global state between instances should it ever matter to you if you. In which case, the idiomatic way of dealing with this is to use a module. The module itself can have "private" classes, e.g. in `my_logger.py`, you have `class _MyImplementationDetail: ...` in it, but the module will take the place of an instance, and you would simply `import my_logger` and that is how client code would use your logger. – juanpa.arrivillaga Sep 16 '18 at 06:35
  • usecase is very simple lets say a class is creating a connection over http, connection once created should be reused because creating a connection is costly operation. I don't want a new http connection to be created everytime a new instance of a class gets created. This is what I prevent using singleton in Java. – Lokesh Agrawal Sep 16 '18 at 06:40
  • @LokeshAgrawal that doesn't make a lot of sense to me. You can re-use a connection without a singleton class. Again, if you are using a singleton, that to me implies *you don't need an instance at all*. – juanpa.arrivillaga Sep 17 '18 at 11:59

1 Answers1

8

The first thing to keep in mind is Python is not Java. It's not as restrictive as other languages. As Guido says, "we're all adults here". Nothing really prevents you from doing most things in Python. The solution is "don't do that".

However, there are several ways to do singletons. Another way, one that looks more "natural" to a user, is to use a factory function that looks like a class instantiation. Here's an example.

class _Singleton:
    _instance = None

    def hello(self):
        print("Hello!")


def Singleton():
    if _Singleton._instance is None:
        _Singleton._instance = _Singleton()
    return _Singleton._instance



s1 = Singleton()
s2 = Singleton()

assert s1 is s2
Keith
  • 37,985
  • 10
  • 48
  • 67
  • I can still do s1 = _Singleton() and s2 = _Singleton(). I agree to your point that we are adults and we should not do wrong things. But I am surprised that we don't enforce things in Python, crazy – Lokesh Agrawal Sep 16 '18 at 06:09
  • True, but the more "advanced" methods of using a metaclass can fix that. But since you seem new to the language I provided a simpler example. That means you have to write it yourself, explicitly. – Keith Sep 16 '18 at 06:12
  • I have added one more implementation which is based on base class that spins my head off (maybe because of Java injection in my blood) – Lokesh Agrawal Sep 16 '18 at 06:17
  • @LokeshAgrawal it is simply overriding the constructor, `__new__`, and simply creates a cache of instances as a class variable (a "static variable" in Java parlance) – juanpa.arrivillaga Sep 16 '18 at 06:27
  • Line this instance = super().__new__(class) scares me, looks like an infinite recursion. – Lokesh Agrawal Sep 16 '18 at 06:34
  • 2
    Please ignore my last comment, after reading about __new__ and __init__, I got to know why this line is there. Thanks for your help here. – Lokesh Agrawal Sep 16 '18 at 15:28