3

I read about multiple approaches of creating a singleton function in this SO question.

I came up with another approach

def my_singleton():

    if not my_singleton.instance:
        class MyClass:
            pass

        my_singleton.instance = MyClass()

    return my_singleton.instance

my_singleton.instance = None

What is wrong with this approach compared to other approaches mentioned in previous SO question? Is there any implication related to memory/GC/thread safety/lifecycle of instance. I am asking this because other approaches looks quite complicated for a beginner (metaclass, decorators, baseclass, decorators returning class)

himanshu219
  • 654
  • 7
  • 22
  • 1
    I am not sure about function approach, but for sure your code does not work producing `AttributeError: 'function' object has no attribute 'instance'` – running.t Jun 26 '18 at 10:47
  • Why do you need a singleton? Just pass the object where it's needed. [Explicit is better than implicit](https://www.python.org/dev/peps/pep-0020/). – Peter Wood Jun 26 '18 at 10:47
  • 1
    You need to set an initial value for `my_singleton.instance`. Other than that, you are just manually caching a value. Nothing wrong with that. – timgeb Jun 26 '18 at 10:47
  • Thanks I missed out the last line. Edited the code. – himanshu219 Jun 26 '18 at 11:24

1 Answers1

2

Apart from an issue with instance attribute (AttributeError: 'function' object has no attribute 'instance') there is another issue with this approach. After creating "almost-singleton" object using my_singleton you can simple get class from that object and create new objects of that class.

x = my_singleton()
y = my_singleton()
x == y
Out[50]: True

z = x.__class__()
type(z) == type(x)
Out[52]: True

z == x
Out[53]: False

BTW. Here is how I fixed your my_singleton() function (not to raise Attribute error, but still it's not a real singleton):

def my_singleton():
    try:
        return my_singleton.instance
    except AttributeError:
        class MyClass:
            pass
        my_singleton.instance = MyClass()
        return my_singleton.instance
running.t
  • 5,329
  • 3
  • 32
  • 50
  • Ah got it thanks. It suffers from the same problem as the decorator approach and does not creates a pure singleton object.Although I couldn't think of a use case where programmers will be using this approach to create an instance(intentionally). Is there any implication related to memory/GC/thread safety/lifecycle of instance? – himanshu219 Jun 26 '18 at 11:45
  • you could plug that hole by **MyClass.inst = None** at class level and, assigning self to it that in \__init\__ and throwing an exception if it was already assigned. – JL Peyret Jun 27 '18 at 06:13