#🔒 python singleton implementation comparison

13 messages · Page 1 of 1 (latest)

robust echo
#

I have the following two classes. Both raise an exception when using constructor a second time, as well as when using get_instance(). Now I'm no Python expert, so:

1) Which one is better?
2) What is the actual difference of using get_isntance() vs using constructor?
3) How do I ensure thread-safety? (Optional, I don't care about this as much right now)

The code:

class Logic:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(Logic, cls).__new__(cls)
        return cls._instance

    def __init__(self, **kwargs):
        # Prevent reinitialization if an instance already exists
        if hasattr(self, '_initialized') and self._initialized:
            raise Exception("This class is a singleton!")

        super(Logic, self).__init__(**kwargs)
        self._initialized = True  # Mark as initialized

    @classmethod
    def get_instance(cls, **kwargs):
        return cls(**kwargs)


class Logic2:
    _instance = None

    def __init__(self, **kwargs):
        # Prevent reinitialization if an instance already exists
        if Logic2._instance:
            raise Exception("This class is a singleton!")

        super(Logic2, self).__init__(**kwargs)
        Logic2._instance = self

    @classmethod
    def get_instance(cls, **kwargs):
        return cls(**kwargs)
swift karmaBOT
#

@robust echo

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

lethal jackal
#

Both of these are strange to me, since IMO one should always be able to do e.g.

a = Logic()
b = Logic()

without fear, and with a singleton it'll simply be true that a is b. Whereas in your implementations you'll get an exception the second time.

#

How do I ensure thread-safety?
Should be as simple as adding a _lock = threading.Lock() classvar and wrapping the __new__ code in with cls._lock:

robust echo
#
import threading

class Logic:
   _lock = threading.Lock()
   _instance = None

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

t1 = Logic()
t2 = Logic()
print(t1 is t2)

Thank you, I was overcomplicating things

weak fulcrum
#
class Logic:
    _lock = threading.Lock()
    _instance = None

    def __new__(cls):
        if self._instance is None:
            cls._instance = ...
        return cls._instance

Etc.
Making a real class variable, having a leading underscore to signal it should be left alone, and checking if it's None.
Feels a bit cleaner than a hasattr check.

#

You also don't need args to super():

super().__new__(cls)
#

And the object inheritance is implied in Python 3: we only needed that explicitly back in the olden days of Py2 🙂

robust echo
#

I updated the code

ashen briar
#

It's worth noting that you can do this using a decorator with like... 5 lines of code

robust echo
swift karmaBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.