Python and Singleton (single-piece) modes [reprint]

Source: Internet
Author: User

An Implementation of Singleton mode in python is as follows:

class Foo: pass
def instance():
global inst
try:
inst
except:
inst = Foo ()
return inst

This implementation is simple and intuitive, but its disadvantages are also obvious:

  1. The customer code needs to explicitly know a method called instance () to create the object of this class;
  2. This implementation is not reliable in a concurrent environment;

2nd is a very serious defect. If you use the above code, you can only pray that more than one instance will appear (although the probability is low, it is still possible ), otherwise, an odd problem may occur.

A slightly better implementation is as follows:

class Singleton(object):   
objs = {}
def __new__(cls, *args, **kv):
if cls in cls.objs:
return cls.objs[cls]
cls.objs[cls] = object.__new__(cls)

This implementation solves the first drawback. For classes that only need one instance to implement the singleton mode, they only need to inherit from the singleton class, no matter where the code instantiates the class, only one instance of this class exists.


To solve the 2nd disadvantages, an evolutionary version emerged as follows:

class Singleton(object):
objs = {}
objs_locker = threading.Lock()

def __new__(cls, *args, **kv):
if cls in cls.objs:
return cls.objs[cls]

cls.objs_locker.acquire()
try:
if cls in cls.objs: ## double check locking
return cls.objs[cls]
cls.objs[cls] = object.__new__(cls)
finally:
cls.objs_locker.release()

Are you familiar with it? By the way, this is the classic double check lock mechanism in singleton mode, which ensures the correct implementation of Singleton mode in the concurrent environment.

So far, the two shortcomings mentioned above have been solved by the evolved code and seem perfect, but the story is not over yet, I wonder if you have any questions about the improved code?


Before proceeding, we will first introduce the basic knowledge about _ new _ and _ init _. The classic and new classes of Python support the _ init _ function, however, only the new classes support the _ new _ function. During the creation of a new class, the python interpreter first calls the _ new _ function of the class to create an instance, then initialize the instance by calling the _ init _ function. If these functions do not exist, the default version of python is called. However, if you provide the implementation of these functions, it will call the version implemented by the user.

The improved Code also has two problems:

  • If the user provides the _ new _ function of the custom version, it will overwrite or interfere with the execution of _ new _ In the singleton class, but the probability of such a situation is very small, because few users customize the creation process of class instances;
  • If the user provides the _ init _ function of the custom version, _ init _ will be called every time the class is instantiated. This is obviously not the case, _ init _ should be called only once during instance creation;

To solve the problem that _ init _ is called multiple times, a more advanced (and more complex) version is as follows:

class Singleton(object):

objs = {}
objs_locker = threading.Lock()

def __new__(cls, *args, **kv):
if cls in cls.objs:
return cls.objs[cls]['obj']

cls.objs_locker.acquire()
try:
if cls in cls.objs: ## double check locking
return cls.objs[cls]['obj']
obj = object.__new__(cls)
cls.objs[cls] = {'obj': obj, 'init': False}
setattr(cls, '__init__', cls.decorate_init(cls.__init__))
finally:
cls.objs_locker.release()

@classmethod
def decorate_init(cls, fn):
def init_wrap(*args):
if not cls.objs[cls]['init']:
fn(*args)
cls.objs[cls]['init'] = True
return

return init_wrap 

Here, you may think: Is it necessary to make a simple task so complicated?

My answer is: depending on the situation.

  • If your runtime environment does not have concurrency, and the customer Code does not care about the extra workload (remember the instance () function), the code at the beginning of this article is the most suitable;
  • Even if a concurrent environment exists, the Customer Code does not care much about the additional workload (except for remembering every instantiated function, but also calling in the same place and ensuring the call sequence, then Initialize all the single-piece instances in the program startup phase. The code at the beginning of this article is quite suitable;
  • If concurrency exists, and the customer is very lazy (lazy is a virtue of programmers), don't want to remember too many things irrelevant to the business, and don't want to concentrate on initializing a single piece, it is also necessary to ensure the initialization order, and centralized Initialization is impossible in some cases (such as a system with plug-ins), so use the last complex code.

 

Gains and Losses

Simple implementation, clear code logic, small maintenance volume, and easy modification, but restricted application environment (as described in the previous two points ), some initialization work is completed by the customer (calling the instance function). This is not a problem in small systems, but in a large system, this will become a significant burden (especially when the names of instantiated functions are not uniform ).

 

Complex implementation: all creation operations are completed in one place, without making assumptions about the environment, without causing any burden to the customer. To use them like normal classes, the most important thing is to create a single piece (base class) it is separated from Business Code (inheritance class) and clearly divided. The disadvantage is that the Code is complex, difficult to maintain and modify, and requires certain Python advanced language features.


Reposted from: Python and Singleton (single-piece) Modes

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.