单例模式 Python语言实现版

目录

一、懒汉式实现

二、饿汉式实现

三、装饰器实现

四、元类实现

五、线程局部实现

六、缓存实现

七、利用__new__方法实现单例模式

总结


单例模式是一种常见的设计模式,它保证了一个类只有一个实例,并提供一个全局访问点来访问该实例。在 Python 中,可以通过多种方式实现单例模式,下面介绍几种常见的实现方式。

一、懒汉式实现

懒汉式实现是在需要使用单例时才创建单例对象,是最简单的实现方式。这种方式实现起来比较简单,但可能会在多线程环境下出现问题。

python 复制代码
class Singleton:  
    __instance = None  
  
    def __new__(cls):  
        if cls.__instance is None:  
            cls.__instance = super().__new__(cls)  
        return cls.__instance

在上面的代码中,我们通过一个私有类变量 __instance 来保存单例实例。在 new 方法中,我们首先判断 __instance 是否为空,如果为空则创建一个新的实例并赋值给 __instance,否则直接返回 __instance。这种方式实现简单,但可能存在线程不安全的问题。

二、饿汉式实现

饿汉式实现是在类定义时就创建单例对象,不管是否需要使用该对象。这种方式实现起来比较简单,且避免了多线程环境下的线程不安全问题。

python 复制代码
class Singleton:  
    __instance = None  
  
    def __new__(cls):  
        if cls.__instance is None:  
            cls.__instance = super().__new__(cls)  
        return cls.__instance

在上面的代码中,我们在类定义时就创建了一个单例对象 __instance。在 new 方法中,我们只需要直接返回 __instance 即可。这种方式实现简单,且避免了多线程环境下的线程不安全问题。但可能会浪费一定的内存空间。

三、装饰器实现

装饰器是一种可以在不改变原有函数或方法的情况下增加新功能的函数或方法。在 Python 中,可以通过装饰器来实现单例模式。这种方式实现起来比较简单,且可以在不需要使用单例对象时自动释放内存空间。

python 复制代码
def singleton(cls):  
    instances = {}  
    def get_instance(*args, **kwargs):  
        if cls not in instances:  
            instances[cls] = super().__new__(cls)  
        return instances[cls]  
    return get_instance

在上面的代码中,我们定义了一个装饰器函数 singleton,它接受一个类作为参数并返回一个新函数。新函数中定义了一个字典 instances 来保存每个类的单例实例。在函数中,我们首先判断该类是否已经在字典中存在单例实例,如果不存在则创建一个新的实例并保存到字典中,否则直接返回已有的单例实例。这种方式实现简单,且可以在不需要使用单例对象时自动释放内存空间。但需要注意在使用装饰器时需要将类作为参数传递给装饰器。

四、元类实现

元类是 Python 中创建类的类。通过元类可以实现单例模式,并且可以在不需要使用单例对象时自动释放内存空间。

python 复制代码
class SingletonType(type):  
    _instances = {}  
    def __call__(cls, *args, **kwargs):  
        if cls not in cls._instances:  
            cls._instances[cls] = super().__call__(*args, **kwargs)  
        return cls._instances[cls]

在上面的代码中,我们定义了一个元类 SingletonType,它继承自内置的 type 类。在元类中,我们定义了一个字典 _instances 来保存每个类的单例实例。在 call 方法中,我们首先判断该类是否已经在字典中存在单例实例,如果不存在则创建一个新的实例并保存到字典中,否则直接返回已有的单例实例。通过这种方式实现单例模式可以保证每个类的单例实例都是唯一的。但需要注意在使用元类时需要将类定义为单例类的子类,并且需要将元类作为参数传递给类定义。

五、线程局部实现

在 Python 中,可以使用 threading 模块的 local() 方法来创建线程局部对象。通过这种方式,可以实现在每个线程中保存单例实例,避免多线程环境下的线程不安全问题。

python 复制代码
import threading  
  
class Singleton:  
    _instance = None  
    _local_instances = {}  
  
    def __new__(cls, *args, **kwargs):  
        instance = cls._local_instances.get(threading.current_thread())  
        if instance is None:  
            instance = super().__new__(cls)  
            cls._local_instances[threading.current_thread()] = instance  
        return instance

在上面的代码中,我们定义了一个类变量 _instance 来保存全局的单例实例,同时定义了一个字典 _local_instances 来保存每个线程的单例实例。在 new 方法中,我们首先判断当前线程是否已经存在单例实例,如果存在则直接返回该实例,否则创建一个新的实例并保存到字典中,并返回该实例。通过这种方式实现单例模式可以保证每个线程的单例实例都是唯一的。但需要注意在使用线程局部对象时需要小心处理线程安全问题。

六、缓存实现

缓存实现是一种利用缓存来保存单例实例的方式。这种方式实现起来比较简单,但可能会浪费一定的内存空间。

python 复制代码
class Singleton:  
    _instance = None  
    _cache = {}  
  
    def __new__(cls, *args, **kwargs):  
        key = (cls, args, frozenset(kwargs.items()))  
        instance = cls._cache.get(key)  
        if instance is None:  
            instance = super().__new__(cls)  
            cls._cache[key] = instance  
        return instance

在上面的代码中,我们定义了一个类变量 _instance 来保存全局的单例实例,同时定义了一个字典 _cache 来保存每个单例实例的缓存。在 new 方法中,我们首先判断该单例实例是否已经存在于缓存中,如果存在则直接返回该实例,否则创建一个新的实例并保存到缓存中,并返回该实例。通过这种方式实现单例模式可以避免重复创建相同的单例实例。但需要注意在使用缓存时需要小心处理缓存失效和内存空间浪费的问题。

七、利用__new__方法实现单例模式

在 Python 中,可以通过重写类的 new 方法来实现单例模式。在 new 方法中,我们可以先尝试获取单例实例,如果获取失败则创建新的单例实例并返回。

python 复制代码
class Singleton:  
    _instance = None  
  
    def __new__(cls, *args, **kwargs):  
        if cls._instance is None:  
            cls._instance = super().__new__(cls)  
        return cls._instance

在上面的代码中,我们定义了一个类变量 _instance 来保存全局的单例实例。在 new 方法中,我们首先判断该单例实例是否已经存在,如果存在则直接返回该实例,否则创建一个新的实例并保存到类变量中,并返回该实例。通过这种方式实现单例模式可以保证每个类的单例实例都是唯一的。但需要注意在使用这种方式时需要小心处理多线程环境下的线程安全问题。

总结

在 Python 中实现单例模式有多种方式,每种方式都有自己的优缺点。在选择实现方式时需要根据具体的应用场景和需求进行选择。同时需要注意在使用单例模式时需要小心处理线程安全和缓存等问题。

相关推荐
古希腊掌管学习的神1 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
半盏茶香1 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Evand J2 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
LucianaiB2 小时前
探索CSDN博客数据:使用Python爬虫技术
开发语言·爬虫·python
Ronin3052 小时前
11.vector的介绍及模拟实现
开发语言·c++
计算机学长大白3 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
PieroPc4 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439697 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna7 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis