Python中使用单例模式创建类

devtools/2024/12/22 21:20:14/

在 Python 中,实现单例模式有多种方式,每种方式都有其优缺点。先上结论,如果对某种实现方式有兴趣的话可以选择性的阅读。


1. 结论

实现方式优点缺点荐语
元类线程安全,灵活实现复杂适合需要灵活性和线程安全的场景
threading.Lock线程安全,实现简单需要使用线程锁适合需要简单实现的场景
模块简单易用,线程安全无法动态创建单例实例想要简单且可以接收静态单例场景
importlib灵活,可动态加载单例实例需要额外的模块支持不推荐
__new__ 方法简单直观非线程安全不推荐
装饰器灵活,可应用于多个类非线程安全不推荐

2. 使用元类

2.1 实现方式

通过自定义元类来控制类的创建过程,确保类只创建一个实例。

2.2 示例代码

python">class SingletonMeta(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)return cls._instances[cls]class Singleton(metaclass=SingletonMeta):def __init__(self, value):self.value = value# 测试
s1 = Singleton(10)
s2 = Singleton(20)
print(s1.value)  # 输出: 10
print(s2.value)  # 输出: 10
print(s1 is s2)  # 输出: True

2.3 优点

  • 线程安全,适合多线程环境。
  • 灵活,可以应用于多个类。

2.4 缺点

  • 实现较为复杂,不易理解。

3. 使用 threading.Lock 实现线程安全的单例

3.1 实现方式

通过 threading.Lock 确保在多线程环境下只创建一个实例。

3.2 示例代码

python">import threadingclass Singleton:_instance = None_lock = threading.Lock()def __new__(cls, *args, **kwargs):if not cls._instance:with cls._lock:if not cls._instance:cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)return cls._instance# 测试
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # 输出: True

3.3 优点

  • 线程安全,适合多线程环境。

3.4 缺点

  • 实现稍微复杂。

4. 使用模块

4.1 实现方式

在 Python 中,模块是天然的单例。因为模块在第一次导入时会被初始化,后续导入时会使用已经初始化的实例。

4.2 示例代码

python"># singleton_module.py
class Singleton:def __init__(self):self.value = "Singleton Instance"instance = Singleton()# 在其他文件中导入
from singleton_module import instanceprint(instance.value)  # 输出: Singleton Instance

4.3 优点

  • 简单易用,Python 原生支持。
  • 线程安全,无需额外处理。

4.4 缺点

  • 无法动态创建单例实例。

5. 使用 importlib 模块

5.1 实现方式

通过 importlib 模块动态导入模块,确保模块只被导入一次。

5.2 示例代码

python">import importlibclass Singleton:_instance = None@staticmethoddef get_instance():if Singleton._instance is None:Singleton._instance = importlib.import_module("singleton_module").instancereturn Singleton._instance# 测试
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
print(s1 is s2)  # 输出: True

5.3 优点

  • 灵活,可以动态加载单例实例。

5.4 缺点

  • 需要额外的模块支持。

6. 使用 __new__ 方法

6.1 实现方式

通过重写类的 __new__ 方法,确保类在创建实例时只返回同一个实例。

6.2 示例代码

python">class Singleton:_instance = Nonedef __new__(cls, *args, **kwargs):if not cls._instance:cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)return cls._instance# 测试
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # 输出: True

6.3 优点

  • 简单直观,易于理解。

6.4 缺点

  • 非线程安全,在多线程环境下可能会创建多个实例。

7. 使用装饰器

7.1 实现方式

通过装饰器将类转换为单例类。

7.2 示例代码

python">def singleton(cls):instances = {}def get_instance(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instance@singleton
class MyClass:def __init__(self, value):self.value = value# 测试
m1 = MyClass(10)
m2 = MyClass(20)
print(m1.value)  # 输出: 10
print(m2.value)  # 输出: 10
print(m1 is m2)  # 输出: True

7.3 优点

  • 灵活,可以应用于多个类。

7.4 缺点

  • 非线程安全,在多线程环境下可能会创建多个实例。

http://www.ppmy.cn/devtools/144139.html

相关文章

Pytorch | 从零构建Vgg对CIFAR10进行分类

Pytorch | 从零构建Vgg对CIFAR10进行分类 CIFAR10数据集Vgg网络结构特点性能应用影响 Vgg结构代码详解结构代码代码详解特征提取层 _make_layers前向传播 forward 训练过程和测试结果代码汇总vgg.pytrain.pytest.py 前面文章我们构建了AlexNet对CIFAR10进行分类: Py…

【计组】实验三 ORI指令设计实验

一、实验目的 1. 理解MIPS处理器指令格式及功能。 2. 掌握ori指令格式与功能。 3. 掌握ModelSim和ISE\Vivado工具软件。 4. 掌握基本的测试代码编写和FPGA开发板使用方法。 二、实验环境 1. 装有ModelSim和ISE\Vivado的计算机。 2. Sword\Basys3\EGo1实验系统。 三、实…

TDengine 新功能 从 CSV 批量创建子表

1. 背景 我们在从一些数据源(比如关系型数据库)批量导入数据前,我们可能需批量创建出所需子表。TDengine 引擎从 v3.3.3.0 版本开始,提供了通过 CSV 文件批量创建子表的功能,使用者只要按约定的格式生成 CSV 文件&…

半导体制造技术导论(第二版)萧宏 第十二章 化学机械研磨工艺

本章要求 1.列出化学机械研磨工艺的应用 化学机械研磨是一种移除工艺技术,结合化学反应和机械研磨去除沉积的薄膜,使表面更加平滑和平坦;也用于移除表面上大量的电介质薄膜,并在硅衬底上形成浅沟槽隔离STI;还可以从晶圆…

ORA-01114 ORA-27072 错误处理方法

Oracle数据库的临时表空间主要用于存储排序操作和其他临时数据,随着时间的推移,这些数据可能会累积并占用大量磁盘空间。 一、问题说明 在创建一张大表的索引时,出现如下错误。 一般出现这种错误,很可能是数据库临时表空间满了或…

Redis(2)常用命令

安装Redis 现在我们安装Redis 5,Redis安装在Linux上面安装,如果想在本机上面安装多个Redis的话,就要使用Docker。 在Ubuntu上面安装: 切换到root用户使用apt命令搜索相关的软件包(apt search redis)apt …

PHPstudy中的数据库启动不了

法一 netstat -ano |findstr "3306" 查看占用该端口的进程号 taskkill /f /pid 6720 杀死进程 法二 sc delete mysql

基于无框力矩电机抱闸实现人形机器人在展会中不依赖悬吊(补充版)

目录: 1 人形机器人在展会中的悬吊状态 2 人形机器人不能长时间站立的原因 3 基于电机抱闸使人形机器长时间站立 4 人形机器人在展会上的高级动作(新增内容) 5 人形机器人在实用场景中必须长时间站立、快速进行 “静-动” 互换 6 人形机…