Advantages and disadvantages of Several implementation methods of the singleton mode in Python, and advantages and disadvantages of python

Source: Internet
Author: User

Advantages and disadvantages of Several implementation methods of the singleton mode in Python, and advantages and disadvantages of python
Singleton Mode

Singleton Pattern)Is a commonly used software design model, the main purpose of this model is to ensureA class only has one instance.. When you want to create only one instance for a class in the system, the single-instance 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 the content of the configuration file needs to be used in many places during the program running, that is, the AppConfig object instance needs to be created in many places, this results in multiple AppConfig instance objects in the system, which seriously wastes memory resources, especially when the configuration file contains a lot of content. In fact, for classes like AppConfig, we hope that only one instance object exists during the program running.

In Python, we can use multiple methods to implement the singleton mode.

 

Methods for implementing Singleton Mode 1. Use modules

In fact,The Python module is the natural Singleton mode.Because the module will generate.pycFile. When the second import is performed, the file is directly loaded..pycFile, instead of 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, consider doing this:

Mysingleton. py

class Singleton(object):    def foo(self):        passsingleton = Singleton()

Save the above Code in the filemysingleton.pyTo be used, directly import the objects in this file into other files. This object is an object in singleton mode.

from a import singleton

 

 

2. Usage class
class Singleton(object):    def __init__(self):        pass    @classmethod    def instance(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instance

Generally, the singleton mode is completed in this way, but there will be problems when multithreading is used.

 

class Singleton(object):    def __init__(self):        pass    @classmethod    def instance(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instanceimport threadingdef task(arg):    obj = Singleton.instance()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()

After the program is executed, the output is as follows:

<__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0><__main__.Singleton object at 0x02C933D0>

It seems that there is no problem, because the execution speed is too fast. If there are some IO operations in the init method, we will find the problem. Next we use time. sleep to simulate

Add the following code to the _ init _ method above:

    def __init__(self):        import time        time.sleep(1)

After the program is re-executed, the result is as follows:

<__main__.Singleton object at 0x034A3410><__main__.Singleton object at 0x034BB990><__main__.Singleton object at 0x034BB910><__main__.Singleton object at 0x034ADED0><__main__.Singleton object at 0x034E6BD0><__main__.Singleton object at 0x034E6C10><__main__.Singleton object at 0x034E6B90><__main__.Singleton object at 0x034BBA30><__main__.Singleton object at 0x034F6B90><__main__.Singleton object at 0x034E6A90>

The problem has occurred! The Single Instance created in the preceding method cannot support multithreading.

 

Solution: Lock! Concurrent execution without locks, serial execution with locks, and lower speed, but ensures data security

import timeimport threadingclass Singleton(object):    _instance_lock = threading.Lock()    def __init__(self):        time.sleep(1)    @classmethod    def instance(cls, *args, **kwargs):        with Singleton._instance_lock:            if not hasattr(Singleton, "_instance"):                Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instancedef task(arg):    obj = Singleton.instance()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()time.sleep(20)obj = Singleton.instance()print(obj)

 

The output is as follows:

<__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110><__main__.Singleton object at 0x02D6B110>

This is almost the case, but there is still a small problem, that is, when the program is executed, the time is executed. after sleep (20), when the following object is instantiated, It is a singleton mode now, but we still apply the lock. This is not very good. Then we will perform some optimization and use the intance method, just change it to the following:

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

In this way, a singleton mode that supports multithreading is complete.

Import timeimport threadingclass Singleton (object): _ instance_lock = threading. lock () def _ init _ (self): time. sleep (1) @ classmethod def instance (cls, * args, ** kwargs): if not hasattr (Singleton, "_ instance"): with Singleton. _ instance_lock: if not hasattr (Singleton, "_ instance"): Singleton. _ instance = Singleton (* args, ** kwargs) return Singleton. _ instancedef task (arg): obj = Singleton. instance () print (obj) for I in range (10): t = threading. thread (target = task, args = [I,]) t. start () time. sleep (20) obj = Singleton. instance () print (obj)Complete code

 

In this way, the Singleton mode is restricted during use. In future instantiation, you must use obj = Singleton. instance ()

If obj = Singleton () is used, this method is not used as a Singleton.

 

3. Implementation Based on the _ new _ Method

Through the above example, we can know that when we implement Singleton,To ensure thread security, you need to add a lock internally.

We know that when we instantiate an objectFirst, the _ new _ method of the class is executed.(When we do not write data, object. _ new _ is called by default __),Instantiate object; ThenExecute the _ init _ method of the class.To initialize this object. All of us can implement the singleton mode based on this.

import threadingclass Singleton(object):    _instance_lock = threading.Lock()    def __init__(self):        pass    def __new__(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            with Singleton._instance_lock:                if not hasattr(Singleton, "_instance"):                    Singleton._instance = object.__new__(cls, *args, **kwargs)        return Singleton._instanceobj1 = Singleton()obj2 = Singleton()print(obj1,obj2)def task(arg):    obj = Singleton()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()

The output is as follows:

<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0>

 

This Singleton mode is used. When an object is instantiated in the future, obj = Singleton () is the same as the method used to instantiate the object in the future ()

 

4. Implement Related Knowledge Based on metaclass
"1. class is created by type. When a class is created, the _ init _ method of the type is automatically executed, and the class () execute the _ call _ method of type (the _ new _ method of the class and the _ init _ method of the class) 2. an object is created by a class. when an object is created, the _ init _ method of the class is automatically executed. The _ call _ method of the object () Execution class """

Example:

Class Foo: def _ init _ (self): pass def _ call _ (self, * args, ** kwargs): passobj = Foo () # execute the _ call _ method of type and call the _ new _ method of the Foo class (Object of type) to create an object, call the _ init _ method of the Foo class (Object of type) to initialize the object. Obj () # execute the _ call _ method of Foo.

 

Usage of metadata

Class SingletonType (type): def _ init _ (self, * args, ** kwargs): super (SingletonType, self ). _ init _ (* args, ** kwargs) def _ call _ (cls, * args, ** kwargs): # cls, that is, print ('cls', cls) obj = cls. _ new _ (cls, * args, ** kwargs) cls. _ init _ (obj, * args, ** kwargs) # Foo. _ init _ (obj) return objclass Foo (metaclass = SingletonType): # specify the type of the created Foo as SingletonType def _ init _ (self ): pass def _ new _ (cls, * args, ** kwargs): return object. _ new _ (cls, * args, ** kwargs) obj = Foo ()

 

Implement Singleton Mode
import threadingclass SingletonType(type):    _instance_lock = threading.Lock()    def __call__(cls, *args, **kwargs):        if not hasattr(cls, "_instance"):            with SingletonType._instance_lock:                if not hasattr(cls, "_instance"):                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)        return cls._instanceclass Foo(metaclass=SingletonType):    def __init__(self,name):        self.name = nameobj1 = Foo('name')obj2 = Foo('name')print(obj1,obj2)

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.