A singleton pattern instance of a Python design pattern

  • 2020-04-02 13:40:03
  • OfStack

Note: Python 2.7 is used.

A simple implementation


class Foo(object):
    __instance = None
    def __init__(self):
        pass
    @classmethod
    def getinstance(cls):
        if(cls.__instance == None):
            cls.__instance = Foo()
        return cls.__instance
if __name__ == '__main__':
    foo1 = Foo.getinstance()
    foo2 = Foo.getinstance()
    print id(foo1)
    print id(foo2)
    print id(Foo())

The first two outputs are the same (id(foo1) is the same as id(foo2)), and the third is different. Here the class method getinstance() is used to get the singleton, but the class itself can be instantiated in a way that doesn't really meet the requirements of the singleton pattern. But there are advantages to doing this, simple code, you agree to call it like this. But it's best to do that in the naming of the class which is a singleton class, like Foo_singleton.

Think another way

The difference between init and new:


class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
if __name__ == '__main__':
    foo = Foo()

The running result is:

init

Here's an example:

class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
    def __new__(cls, *args, **kwargs):
        print 'new'
if __name__ == '__main__':
    foo = Foo()

The running result is:
new

New is a class method that is called when an object is created. The init method is called after the object is created, and does some initialization on the current object's instance, with no return value. If you overwrite new without calling init in new or without returning an instance, then init will not work. The following quote from http://docs.python.org/2/reference/datamodel.html#object.new


If __new__() returns an instance of cls, then the new instance's __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().
If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked.

To do this:

class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
    def __new__(cls, *args, **kwargs):
        print 'new'
        if cls.__instance == None:
            cls.__instance = cls.__new__(cls, *args, **kwargs)
        return cls.__instance
if __name__ == '__main__':
    foo = Foo()

      The error is as follows:


RuntimeError: maximum recursion depth exceeded in cmp

And here's the mistake:


class Foo(object):
    __instance = None
    def __init__(self):
        if self.__class__.__instance == None:
            self.__class__.__instance = Foo()
        print 'init'
if __name__ == '__main__':
    foo = Foo()

How do you do that?

The following reference http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/31887#31887:


class Foo(object):
    __instance = None
    def __new__(cls, *args, **kwargs):
        print 'hhhhhhhhh'
        if not cls.__instance:
            cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return cls.__instance
    def hi(self):
        print 'hi, world'
        print 'hi, letian'
if __name__ == '__main__':
    foo1 = Foo()
    foo2 = Foo()
    print id(foo1)
    print id(foo2)
    print isinstance(foo1, object)
    print isinstance(foo1, Foo)
    foo1.hi()

Operation results:

hhhhhhhhh
hhhhhhhhh
39578896
39578896
True
True
hi, world
hi, letian

So, what's going on, let's go back to super:


>>> print super.__doc__
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

You can be sure that this line of code in the singleton pattern code above:

cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)

Super (Foo, CLS) is object. Super (Foo, CLS). The new method USES the new method of object. Let's see what the object.new method does:

>>> print object.__new__.__doc__
T.__new__(S, ...) -> a new object with type S, a subtype of T

If it's an inheritance chain


class Fo(object):
    def __new__(cls, *args, **kwargs):
        print 'hi, i am Fo'
        return  super(Fo, cls).__new__(cls, *args, **kwargs)
class Foo(Fo):
    __instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            print Foo is cls
            print issubclass(cls, Fo)
            print issubclass(cls, object)
            cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return cls.__instance
    def hi(self):
        print 'hi, world'
if __name__ == '__main__':
    foo1 = Foo()
    foo1.hi()
    print isinstance(foo1, Foo)
    print isinstance(foo1, Fo)
    print isinstance(foo1, object)

The operation results are as follows:

True
True
True
hi, i am Fo
hi, world
True
True
True

If Fo is defined as follows, it also works normally:

class Fo(object):
    pass

However, if defined as:

class Fo(object):
    def __new__(cls, *args, **kwargs):
        print 'hi, i am Fo'

The error of operation times is as follows:

AttributeError: 'NoneType' object has no attribute 'hi'


Related articles: