6
class Singleton:

    instance = None

    def __new__(cls):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

singleton_obj1 = Singleton()
singleton_obj2 = Singleton()

print(singleton_obj1)
print(singleton_obj2)

output

<__main__.Singleton object at 0x10dbc0f60>
<__main__.Singleton object at 0x10dbc0f60>

Can someone explain what exactly happening at this line cls.instance = super().__new__(cls). Which lines of code helped to make this class Singleton?

phani
  • 3,123
  • 7
  • 33
  • 62
  • That's a pretty bad singleton implementation, by the way. It'll call `__init__` every time you call `Singleton()`, so your singleton will keep getting its attributes reset. (If you have an `__init__` method) – Aran-Fey Jun 11 '18 at 19:48
  • @Aran-Fey can you provide some links to better implementations – phani Jun 11 '18 at 19:50
  • 1
    Here: https://stackoverflow.com/a/6798042/1222951 – Aran-Fey Jun 11 '18 at 19:51
  • 1
    `__new__` is not the same as `__init__`. In fact, for this implementation `__new__` is the correct magic, because a Singleton does not need to be initialized if one instance already exists. Here's a blog that explains the difference: http://howto.lintel.in/python-__new__-magic-method-explained/ – VoNWooDSoN Jun 11 '18 at 20:09

2 Answers2

8

The constructor says,

If there is no instance recorded, 
   create an instance and record it
return the recorded instance

This is a standard singleton design pattern, for most languages, to ensure that only one instance of the class is ever created.

Dragonthoughts
  • 2,069
  • 8
  • 20
  • 23
  • why singleton_obj1 and singleton_obj2 did not get separate copies of `instance`? – phani Jun 11 '18 at 19:43
  • 2
    @LokeshCherukuri Because `instance` is a class variable, not an instance variable. – Aran-Fey Jun 11 '18 at 19:44
  • 1
    When `Singleton()` is called for the second time, `instance` is not `None`, so the `if` does not go ahead and make a new instance. The previous instance is returned. – quamrana Jun 11 '18 at 19:44
  • Because a Singleton should, by definition always return the same instance. For example, a factory class, should only be constructed once, but used in many places, so it should be made a Singleton. – Dragonthoughts Jun 11 '18 at 19:45
8

Ok, to go over this in painful detail:

class Singleton: implicitly inherits from Object because in python everything is an Object.

instance = None is only read at module load time, and sets the class level variable instance to be None one time but it can be over written by individual instances of the class Singleton.

def __new__(cls):
    if cls.instance is None:
        cls.instance = super().__new__(cls)
    return cls.instance

(First off, I think that it's weird that they put "cls" in there, I know why they did it, because it's referring to the class overall and not a specific instance of that class. But, it can be confusing so someone who doesn't know what they're looking at. Anyway...)

__new__ is a magic function that is called before __init__, that is roughly analogous to allocating the space for the new instance of the class. Here, cls.instance was set to None on module load, and so every time a new Singleton is being created this test is done. Since cls.instance is set the first time a Singleton is created, the super().__new__(cls) is also only called once. The super class of Singleton is Object. So the behavior of the super().__new__(cls) is exactly what you'd expect it to be for any other class you create.
If, you are creating a second(, or third/fourth/fifth...) instance of Singleton then this super().__new__(cls) will not be called. Instead the class level variable instance is returned, meaning that no new instances of Singleton can be created.

When you print the instances of Singleton then you can see the memory address of 0x10dbc0f60 is the same for both "instances" because cls.instance is returned at __new__ time, which you can think of as memory allocation time, before __init__ is called.

This is a good way to do a Singleton pattern because in order to create a singleton class, now, all you have to do is inherit from Singleton and the heavy lifting is already done. You go ahead and use __init__ like you normally would, and don't worry about it. Every time you go to create a "new" instance of that class, you'll get the same instance back. Totally behind the scenes.

This is pretty advanced stuff, but look how simple it is. python is the best!

VoNWooDSoN
  • 900
  • 7
  • 12