python中实现单例模式的几种方法

单例模式:一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象,都是指向同一个内存地址,仅仅只有一个实例(只有一个对象)。主要有几种方法来实现:

一、通过导入的方式。

  1.基本原理:当我们导入一个py文件,会执行这个模块的代码,然后将这个模块的名称空间加载到内存。当再次导入时,不会再执行该文件,而是直接在内存中找。因此,如果第一次导入模块,执行文件源代码时实例化了一个类,那再次导入的时候,就不会再实例化。

  2.代码实现:

# cls_singleton.py
class Foo(object):
  pass
 
instance = Foo()
 
# test.py
import cls_singleton
 
obj1 = cls_singleton.instance
obj2 = cls_singleton.instance
print(obj1 is obj2)  # True  

二、通过类中的__new__实现。

  1.代码实现:


class Singleton:
__instance = None
def __init__(self,num):
self.num =num

def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = super().__new__(cls) # 调用父类的__new__方法
return cls.__instance

a = Singleton(10)
b = Singleton(10)
print(id(a)) # 1873004801808
print(id(b)) # 1873004801808
 # 上述单例模式,实例化后只有一个实例化对象。内存地址一致。

三、通过装饰器实现。

def decorator(cls):
    instance = {}
    def func(*args,**kwargs):
        if cls in instance:
            return instance[cls]
        else:
            # 如果类不在字典中,通过cls创建类的实例对象并添加到这个instance字典中(cls是指向这个类的)
            instance[cls] = cls(*args,**kwargs)
            return instance[cls]
    return func

@decorator
class A:
    def __init__(self,name):
        self.name = name

a = A('shao')
b = A('bruce')
print(id(a))
print(id(b))

针对通过__new__这种方法其实看似已经很完美了,如果同时有多个线程同一时刻(极端条件下)事例化对象,那么就会出现多个对象,这就不再是单例模式了。那么解决这个问题,可以通过加锁来解决。

这样一来只有第一个抢到锁的线程实例化一个对象并保存在_instance中,同一时刻抢锁的其他线程再抢到锁后,不会进入这个判断if not cls._instance,直接把保存在_instance的对象返回了。这样就实现了多线程下的单例模式。

此时还有一个问题需要解决,后面所有再事例对象时都需要再次抢锁,这会大大降低执行效率。解决这个问题也很简单,直接在抢锁前,判断下是否有单例对象了,如果有就不再往下抢锁了。

四、__new__圆满版:

import threading
class Singleton:
    __instance = None
    __lock = threading.RLock() # 加锁
    def __init__(self):
        pass
       

    def __new__(cls, *args, **kwargs):
        if cls.__instance:  # 如果已经有了单例就不再去抢锁,避免IO等待
            return cls.__instance
        with cls.__lock:  
            if not cls.__instance:
                print('create')
                cls.__instance = super().__new__(cls) # 调用父类的__new__方法
            return cls.__instance

a = Singleton()
b = Singleton()

 

五、基于元类type:

 1 class Mytype(type):
 2 
 3     def __init__(self,name,bases,attrs):
 4         super(Mytype, self).__init__(name,bases,attrs)
 5         self.instance = None
 6 
 7     def __call__(self, *args, **kwargs):
 8         # 1.判断下是否已有对象
 9         if not self.instance:
10             self.instance = self.__new__(self)
11         self.__init__(self.instance, *args, **kwargs)
12         return self.instance
13 
14 class Singleton(object,metaclass=Mytype):
15     pass
16 
17 class Foo(Singleton):
18     pass
19 
20 a = Foo()
21 b = Foo()
22 print(id(a))
23 print(id(b))

 

详细参考了:https://www.cnblogs.com/wozijisun/p/16635365.html

posted on 2022-09-15 14:48  一先生94  阅读(1927)  评论(0编辑  收藏  举报

导航