Four ways in Python singleton mode

Singleton Pattern is a common software design pattern. The main purpose of this pattern is to ensure that only one instance of a class exists. When you want to have only one instance of a class in the whole system, a singleton object can be used.

For example, the configuration information of a server program is stored in a file, and the client reads the configuration file information through an AppConfig class. If you need to use the content of the configuration file in many places during the running of the program, that is to say, you need to create instances of AppConfig objects in many places, which leads to multiple AppConfig instance objects in the system, and this will seriously waste memory resources, especially in the case of a lot of content in the configuration file. In fact, for a class like AppConfig, we want only one instance object to exist during program execution.

In Python, we can implement the singleton mode in several ways:

1. Use module

You can refer to the user-defined add, delete, modify and query component site object, which is an obvious single interest mode

In fact, Python module is a natural singleton mode, because. pyc file will be generated when the module is imported for the first time. When the module is imported for the second time, the. pyc file will be loaded directly, and the module code will not be executed again. Therefore, we only need to define the relevant functions and data in one module to get a singleton object. If we really want a singleton class, consider this:

# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass
 
my_singleton = My_Singleton()

Save the above code in the file mysingleton.py, and use it as follows:

from mysingleton import my_singleton
 
my_singleton.foo()

2. Use new

from django.test import TestCase

# Create your tests here.
class Singleton:
    def __init__(self,name):
        self.name=name

    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls)
        return cls._instance

one = Singleton('aa')
two = Singleton('bb')
print(one.name)
print(one.name)



two.a = 3
print(one.a)
# one and two are exactly the same. You can use id(), ==, is to detect
print(id(one))
print(id(two))
print(one == two)
print(one is two)

Lock up

import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()
    def __init__(self):
        time.sleep(1)
        print(self)


    def __new__(cls, *args, **kwargs):
        with cls._instance_lock:
            if not hasattr(Singleton,'_instance'):
                Singleton._instance=object.__new__(cls)
        return Singleton._instance



def task():
    obj = Singleton()

for i in range(10):
    t=threading.Thread(target=task)
    t.start()

3. Implement the singleton mode with classes:

a. Multithreaded singleton mode is not supported

class Singleton(object):

    @classmethod
    def instance(cls,*args,**kwargs):
        if not  hasattr(Singleton,'_instance'):
           
            Singleton._instance=Singleton()
        return Singleton._instance


a=Singleton.instance()
b=Singleton.instance()
print(a==b)#True

But let's try with multithreading

import time
class Singleton(object):
    def __init__(self):
        time.sleep(1)

    @classmethod
    def instance(cls,*args,**kwargs):
        if not  hasattr(Singleton,'_instance'):

            Singleton._instance=Singleton()
        return Singleton._instance


# a=Singleton.instance()
# b=Singleton.instance()
# print(a==b)
import threading
def task():

    obj = Singleton.instance()
    print(obj)


for i in range(10):
    t=threading.Thread(target=task)
    t.start()

result:

D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/Singleton mode/class.py
<__main__.Singleton object at 0x0000022E579C6E80>
<__main__.Singleton object at 0x0000022E579AB898>
<__main__.Singleton object at 0x0000022E579EC6A0>
<__main__.Singleton object at 0x0000022E579DB1D0>
<__main__.Singleton object at 0x0000022E579EC5C0>
<__main__.Singleton object at 0x0000022E579D1FD0>
<__main__.Singleton object at 0x0000022E579D9C50>
<__main__.Singleton object at 0x0000022E579C6F60>
<__main__.Singleton object at 0x0000022E579D1EB8>
<__main__.Singleton object at 0x0000022E579DB2B0>

Process finished with exit code 0

b. To solve the above problems, implement a single column mode that supports multiple threads:

'''
//No one answers the questions? Xiaobian created a Python learning exchange QQ group: 579817333 
//Looking for like-minded small partners, mutual help, there are good video learning tutorials and PDF ebooks in the group!
'''
import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()
    def __init__(self):

        time.sleep(1)

    @classmethod
    def instance(cls,*args,**kwargs):
        with cls._instance_lock:
            if not hasattr(Singleton,'_instance'):
                Singleton._instance=Singleton()
                return Singleton._instance
            return Singleton._instance

def task():

    obj = Singleton.instance()
    print(obj)


for i in range(10):
    t=threading.Thread(target=task)
    t.start()

result:

D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/Singleton mode/class.py
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>

Process finished with exit code 0

Question:

To create an instance, you can only call Singleton.instance(), not Singleton()

4, Implementation based on metaclass

1. An object is a class creation. When an object is created, the class's init method is automatically executed, and the object () executes the class's call method
2. The class is created by type. When the class is created, the init method of the type is automatically executed, and the class () executes the call method of the type (the new method of the class, the init method of the class)

# Step 0: execute type's init method [the class is the object of type]
class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        pass

# Step 1: execute the call method of type
#        1.1 call the new method of Foo class (the object of type) to create the object.
#        1.2 call the init method of Foo class (the object of type) to initialize the object.
obj = Foo()
# Step 2: execute the foodef call method
obj()
class SingletonType(type):
    def __init__(self,*args,**kwargs):
        print(1)
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):
        print(2)
        obj = cls.__new__(cls,*args, **kwargs)
        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
        return obj

class Foo(metaclass=SingletonType):
    def __init__(self,name):
        print(4)
        self.name = name
    def __new__(cls, *args, **kwargs):
        print(3)
        return object.__new__(cls)

obj1 = Foo('name')

Implementation of single example

import threading
class Singleton(type):
    _instance_lock=threading.Lock()
    def __call__(cls, *args, **kwargs):
        with  cls._instance_lock:
            if not hasattr(cls,'_instance'):
                cls._instance=super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance


class Foo(metaclass=Singleton):
    def __init__(self,name):
        self.name=name


obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)

Keywords: Python Django

Added by Andrew R on Mon, 20 Apr 2020 18:53:38 +0300