0

My attempt was to create the default instance from inside of a metaclass, but to no avail. At least the reported class is the singleton in the example bellow.

EDIT: Clarifying requirements here: a singleton comparable by using the is keyword, without having to instantiate/call it. Unfortunately, this well known question-answer here doesn't seem to address that.

class MyNormalClass:
    def __init__(self, values):
        self.values = values


class MySingleton(MyNormalClass, type):
    def __new__(mcs, *args, **kwargs):
        return MyNormalClass(["default"])


print(MySingleton)
# <class '__main__.MySingleton'>

print(MySingleton.values)
# AttributeError: type object 'MySingleton' has no attribute 'values'
dawid
  • 663
  • 6
  • 12
  • Possible duplicate: [creating-a-singleton-in-python](https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python) – Patrick Artner Oct 10 '20 at 13:52
  • @PatrickArtner Thanks, I've added details about issues not completely addressed there. – dawid Oct 11 '20 at 08:13

1 Answers1

1

Metaclasses for singletons are overkill. (Search my answers for that, and there should be about 10 occurrences of this phrase).

In your example code in the question, the code inside the class and the metaclass methods is not even being run, not once. There is no black-magic in Python - the program just runs, and there are a few special methods marked with __xx__ that will be called intrinsically by the language runtime. In this case, the metaclass __new__ will be called whenever you create a new class using it as the metaclass, which you code does not show. And also, it would create a new instance of your "singleton" class each time it were used.

In this case, if all you need is a single instance, just create that instance, and let that one be public, instead of its class. You can even us the instance itself to shadow the class from the module namespace, so no one can instantiate it again by accident. If you want values to be immutable, well, you can't ensure that with pure Python code in any way, but you can make changing values do not work casually with = so that people will know they should not be changing it:


class MySingleton:
    __slots__ = ("values",)
    def __init__(self, values):
        self.values = values
        def lock(self, name, value):
             raise TypeError("Singleton can't change value")
        self.__class__.__setitem__ = lock



MySingleton = MySingleton(["values"])
Axe319
  • 4,255
  • 3
  • 15
  • 31
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • It seems much simpler, thanks, I will check if I forgot any reason to have had reached my complicated last attempt. – dawid Oct 12 '20 at 21:30