python单例的几种实现方式

通过__new__()函数

class Testclass(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if Testclass._instance:
            return Testclass._instance
        else:
            Testclass._instance = super().__new__(cls)
            return Testclass._instance


a = Testclass()
b = Testclass()
print(a == b)

该方法如果类中重写了__init__()函数后会出现问题,因为__new__是类实例化时创建实例的函数,而__init__是类实例化中创建实例后初始化实例属性值的函数,__init__函数调用在__new__函数之后,所以用该方法创建单例时,虽然类实例化时__new__每次返回的都是同一个实例对象,但是在实例化的过程中调用__new__函数后会把__new__函数的结果作为__init__函数的参数再次调用__init__函数,这就意味着虽然每次实例化得到的结果都是同一个对象,但是每次实例化都会初始化一次实例的属性值。

通过函数装饰器

def singleton(cls):
    _instance = {}

    def inner():
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    return inner
    
@singleton
class Testclass(object):
    def __init__(self):
        pass

a = Testclass()
b = Testclass()
print(a == b)

使用模块

模块天然就是单例的,因为模块只会被加载一次,加载之后,其他脚本里如果使用import 二次加载这个模块时,会从sys.modules里找到已经加载好的模块,模块里的对象天然就是单例的,即使是在多线程环境下也是如此。

编写py文件my_singleton.py

class Singleton():
    def __init__(self, name):
        self.name = name

    def do_something(self):
        pass

singleton = Singleton('模块单例')

在其他文件中引入
from my_singleton import singleton
在任何引用singleton的脚本里,singleton都是同一个对象,这就确保了系统中只有一个Singleton的实例。

使用类方法

class Singleton(object):

    def __init__(self, name):
        self.name = name

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

single_1 = Singleton.instance('第1次创建')
single_2 = Singleton.instance('第2次创建')

print(single_1 is single_2)

instance方法会先检查是否存在类属性_instance, 如果不存在,则创建对象,并返回。这个设计虽然实现了单例模式,但在多线程环境下不安全,多个线程同时检查Singleton类是否拥有_instance属性,得到的结果是否False, 则这些线程都会执行对象的创建工作,最后创建出来的对象才是最终的对象,为了在多线程环境下保证数据安全,在需要并发枷锁的地方加上RLock锁

from threading import RLock
class Singleton(object):
    single_lock = RLock()

    def __init__(self, name):
        self.name = name

    @classmethod
    def instance(cls, *args, **kwargs):
        with Singleton.single_lock:
            if not hasattr(Singleton, "_instance"):
                Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容