Singleton mode of Python

Keywords: Python

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. Singleton objects come in handy when you want only one instance of a class in the whole system.

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 the contents of the configuration file need to be used in many places during the running of the program, that is, instances of AppConfig objects need to be created in many places, which will lead to multiple AppConfig instance objects in the system, which will seriously waste memory resources, especially when there are many contents of the configuration file. In fact, for classes like AppConfig, we want only one instance object to exist during the program running.

In Python, we can implement singleton mode in many ways:

1. Use the module

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

In fact, Python's module is a natural singleton mode, because when the module is imported for the first time, it will generate a. pyc file. When it is imported for the second time, it will directly load the. pyc file without executing the module code again. Therefore, we only need to define the relevant functions and data in a module to obtain a singleton object. If we really want a singleton class, we can consider doing this:

    
  1. # mysingleton.py
  2. class My_Singleton(object):
  3.     def foo(self):
  4.         pass
  5. my_singleton = My_Singleton()

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

    
  1. from mysingleton  import my_singleton
  2. my_singleton.foo()

2. Use new

    
  1. #Python learning communication QQ group: 579817333
  2. from django.test  import TestCase
  3. # Create your tests here.
  4. class Singleton:
  5.     def __init__(self,name):
  6.         self.name=name
  7.     def __new__(cls, *args, **kw):
  8.          if not hasattr(cls,  '_instance'):
  9.             orig = super(Singleton, cls)
  10.             cls._instance = orig.__new__(cls)
  11.          return cls._instance
  12. one = Singleton( 'aa')
  13. two = Singleton( 'bb')
  14. print(one.name)
  15. print(one.name)
  16. two.a =  3
  17. print(one.a)
  18. #  one and two are exactly the same. You can use id(),  ==,  is detection
  19. print(id(one))
  20. print(id(two))
  21. print(one == two)
  22. print(one is two)

Lock

    
  1. import time
  2. import threading
  3. class Singleton(object):
  4.     _instance_lock = threading.Lock()
  5.     def __init__(self):
  6.         time.sleep( 1)
  7.          print(self)
  8.     def __new__(cls, *args, **kwargs):
  9.         with cls._instance_lock:
  10.              if not hasattr(Singleton, '_instance'):
  11.                 Singleton._instance=object.__new__(cls)
  12.          return Singleton._instance
  13. def task():
  14.     obj = Singleton()
  15. for i in  range( 10):
  16.     t=threading.Thread(target=task)
  17.     t.start()

3. Implement singleton mode by using class:

a. Cannot support multi-threaded singleton mode

    
  1. class Singleton(object):
  2.     @classmethod
  3.     def instance(cls,*args,**kwargs):
  4.          if not  hasattr(Singleton, '_instance'):
  5.             Singleton._instance=Singleton()
  6.          return Singleton._instance
  7. a=Singleton.instance()
  8. b=Singleton.instance()
  9. print(a==b)#True

But let's try with multithreading

    
  1. import time
  2. class Singleton(object):
  3.     def __init__(self):
  4.         time.sleep( 1)
  5.     @classmethod
  6.     def instance(cls,*args,**kwargs):
  7.          if not  hasattr(Singleton, '_instance'):
  8.             Singleton._instance=Singleton()
  9.          return Singleton._instance
  10. # a=Singleton.instance()
  11. # b=Singleton.instance()
  12. #  print(a==b)
  13. import threading
  14. def task():
  15.     obj = Singleton.instance()
  16.      print(obj)
  17. for i in  range( 10):
  18.     t=threading.Thread(target=task)
  19.     t.start()

result:

    
  1. D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/Singleton mode/class.py
  2. <__main__.Singleton object at  0x0000022E579C6E80>
  3. <__main__.Singleton object at  0x0000022E579AB898>
  4. <__main__.Singleton object at  0x0000022E579EC6A0>
  5. <__main__.Singleton object at  0x0000022E579DB1D0>
  6. <__main__.Singleton object at  0x0000022E579EC5C0>
  7. <__main__.Singleton object at  0x0000022E579D1FD0>
  8. <__main__.Singleton object at  0x0000022E579D9C50>
  9. <__main__.Singleton object at  0x0000022E579C6F60>
  10. <__main__.Singleton object at  0x0000022E579D1EB8>
  11. <__main__.Singleton object at  0x0000022E579DB2B0>
  12. Process finished with exit code  0

b. Solve the above problems and realize the single column mode supporting multithreading:

    
  1. import time
  2. import threading
  3. class Singleton(object):
  4.     _instance_lock = threading.Lock()
  5.     def __init__(self):
  6.         time.sleep( 1)
  7.     @classmethod
  8.     def instance(cls,*args,**kwargs):
  9.         with cls._instance_lock:
  10.              if not hasattr(Singleton, '_instance'):
  11.                 Singleton._instance=Singleton()
  12.                  return Singleton._instance
  13.              return Singleton._instance
  14. def task():
  15.     obj = Singleton.instance()
  16.      print(obj)
  17. for i in  range( 10):
  18.     t=threading.Thread(target=task)
  19.     t.start()

result:

    
  1. D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/Singleton mode/class.py
  2. <__main__.Singleton object at  0x000001BADB56F320>
  3. <__main__.Singleton object at  0x000001BADB56F320>
  4. <__main__.Singleton object at  0x000001BADB56F320>
  5. <__main__.Singleton object at  0x000001BADB56F320>
  6. <__main__.Singleton object at  0x000001BADB56F320>
  7. <__main__.Singleton object at  0x000001BADB56F320>
  8. <__main__.Singleton object at  0x000001BADB56F320>
  9. <__main__.Singleton object at  0x000001BADB56F320>
  10. <__main__.Singleton object at  0x000001BADB56F320>
  11. <__main__.Singleton object at  0x000001BADB56F320>
  12. 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. The object is the init of the class when creating the object__ Method is executed automatically, and the object () executes the of the class_ call_ Method 2. The class is created by type. When creating the class, type_ init_ Method is executed automatically, and class () executes type_ call_ Method (class's _new method, class's init method)

    
  1. #Python learning communication QQ group: 579817333
  2. #  The first 0 step: implement type of __init__ Method class is type [object]
  3. class Foo:
  4.     def __init__(self):
  5.         pass
  6.     def __call__(self, *args, **kwargs):
  7.         pass
  8. #  The first 1 step: implement type of __call__ method
  9. #        1.1  call Foo Class (yes) type Object) __new__Method to create an object.
  10. #        1.2  call Foo Class (yes) type Object) __init__Method to initialize an object.
  11. obj = Foo()
  12. #  The first 2 Step: Execute Foodef __call__ method
  13. obj()
    
  1. class SingletonType( type):
  2.     def __init__(self,*args,**kwargs):
  3.          print( 1)
  4.         super(SingletonType,self).__init__(*args,**kwargs)
  5.     def __call__(cls, *args, **kwargs):
  6.          print( 2)
  7.         obj = cls.__new__(cls,*args, **kwargs)
  8.         cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
  9.          return obj
  10. class Foo(metaclass=SingletonType):
  11.     def __init__(self,name):
  12.          print( 4)
  13.         self.name = name
  14.     def __new__(cls, *args, **kwargs):
  15.          print( 3)
  16.          return object.__new__(cls)
  17. obj1 = Foo( 'name')

Implementation of singleton

    
  1. import threading
  2. class Singleton( type):
  3.     _instance_lock=threading.Lock()
  4.     def __call__(cls, *args, **kwargs):
  5.         with  cls._instance_lock:
  6.              if not hasattr(cls, '_instance'):
  7.                 cls._instance=super(Singleton, cls).__call__(*args, **kwargs)
  8.          return cls._instance
  9. class Foo(metaclass=Singleton):
  10.     def __init__(self,name):
  11.         self.name=name
  12. obj1 = Foo( 'name')
  13. obj2 = Foo( 'name')
  14. print(obj1,obj2)

(end)

Posted by jamal dakak on Mon, 13 Sep 2021 12:47:47 -0700