0

I want to make a python singleton class and so that the instance of that class is exactly the same when everywhere else in the code calls the class after the program is on.

I tried to find singleton example and found one from link: https://wikidocs.net/3693

class Singleton(object):
    _instance = None
    def __new__(class_, *args, **kwargs):
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance

and then testing like this

class Test(Singleton):
    def __init__(self, name=None):
        print(name)

test1 = Test('a')

expecting to show name that is given when it is initialized but this gives me an error

TypeError                                 Traceback (most recent call last)
<ipython-input-55-f3383e846037> in <module>()
----> 1 test1 = Test('a')

<ipython-input-33-222ac7a13884> in __new__(class_, *args, **kwargs)
     27     def __new__(class_, *args, **kwargs):
     28         if not isinstance(class_._instance, class_):
---> 29             class_._instance = object.__new__(class_, *args, **kwargs)
     30         return class_._instance

TypeError: object() takes no parameters

But when I try this, this one success

Test() # with no prarameter
test1 = Test('a') # this prints 'a' without error

I would like to know how to fix this. Otherwise, I have to initialize without parameters at the beginning when I start the program.

The reason I want to get the parameter is that when the parameter is changed at some point then I want to apply the changed information to everywhere that calls this class.

juanpa.arrivillaga
  • 65,257
  • 7
  • 88
  • 122
Isaac Sim
  • 439
  • 6
  • 17

1 Answers1

1

The singleton pattern is pretty pointless in Python. Almost always, you are just better off using a module. Or some factory function as your main construction API, e.g. getLogger.

If you really insist on making your class superficially a singleton (this can always be subverted), i'd suggest the metaclass approach because it side-steps all sorts of complications of overriding __new__, although, metaclasses introduce their own complications.

But to address your question, this code is outdated, passing arguments to object.__new__ will now throw an error instead of being simply ignored. To make this work, simply do not pass any arguments to __new__:

In [1]: class Singleton(object):
   ...:     _instance = None
   ...:     def __new__(class_, *args, **kwargs):
   ...:         if not isinstance(class_._instance, class_):
   ...:             class_._instance = object.__new__(class_)
   ...:         return class_._instance
   ...:

In [2]: class Test(Singleton):
   ...:     def __init__(self, name=None):
   ...:         print(name)
   ...:
   ...: test1 = Test('a')
a

Note, __init__ will be called each time you "instantiate" your singleton:

In [3]: test2 = Test('b')
b

In [4]: test1 is test2
Out[4]: True

Which may or may not be desirable.

But seriously reconsider if you need a singleton classes. Even in languages where they sort of make sense, e.g. Java, they are often an anti-pattern, and are merely a way to hide mutable global state in an OOP-encapsulated façade. Which again, brings me to the original suggestion of just using a module, then you have no pretense.

juanpa.arrivillaga
  • 65,257
  • 7
  • 88
  • 122
  • Thank you for your considerable thoughts and answer, but I mentioned at the beginning I want this class to be used in everywhere in the program exactly same. If any change of attribute is occurred then I want it to be uniformly used in else where as well. That is the purpose of using singleton... – Isaac Sim Oct 07 '20 at 03:16
  • Your answer works as exactly I wanted it to be. Thank you again – Isaac Sim Oct 07 '20 at 03:18
  • @IsaacSim right, *exactly* that's my point, you want to use mutable, global state. You could just use a module. But if this is what you are looking I'm glad you've solved your issue – juanpa.arrivillaga Oct 07 '20 at 03:29