实现单例模式的几种方式

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,
当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
如果我们真的想要一个单例类,可以考虑这样做
1.创建test1.py文件,添加以下代码

class Sington:
    def __init__(self,*args,**kwargs):
        self.name = args[0]
        self.age = kwargs["age"]

sington = Sington("nick",age=23)

2.创建test2.py文件,在test2.py文件里面导入test1.py文件里面的sington

from test1 import sington

print(sington.name)

使用装饰器实现单例模式

代码如下:代码的思想就是在装饰器里面放一个字典,这个字典会存放所有需要使用单例模式的类的映射.
当不存在映射时,就创建一个对象进去,存在就略过

from functools import wraps
def sington(cls):
    _instances = {}
    @wraps(cls)
    def wrapper(*args,**kwargs):
        if cls not in _instances:
            _instances[cls] = cls(*args,**kwargs)
        return _instances[cls]

    return wrapper


@sington
class Test:
    def __init__(self,*args,**kwargs):
        pass


test1 = Test()
test2 = Test()
print(id(test1) == id(test2))  # True

使用类的方式 (保证线程安全)

有陷阱的创建方式: 线程不安全

# 由于实例化对象的时候先调用__new__方法,再调用__init__方法,如果__init__出现耗时操作,比如数据库连接
# 读取文本之类的,就会造成多线程并发的情况下(时间片轮转)多个线程同时调用了instance方法.
# 就会造成多个对象出来,虽然最后一个执行完的线程制造的对象会覆盖掉之前创建的对象,
# 但依然是不安全的
import threading
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(*args, **kwargs)
        return Singleton._instance



def task():
    obj = Singleton.instance()
    print(id(obj))

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

解决方法:枷锁

import time
import threading
class 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._instance


def task():
    obj = Singleton.instance()
    print(id(obj))
list1 = list()
for i in range(10):
    t = threading.Thread(target=task)
    t.start()
    list1.append(t)
for i in list1:
    i.join()
obj = Singleton.instance()
print(obj)

方式三:基于new的线程安全

import threading
class 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)  
        return Singleton._instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)

def task():
    obj = Singleton()
    print(obj)

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

你可能感兴趣的:(实现单例模式的几种方式)