python中单例模式介绍(含线程安全的单例模式)

理解单例模式之前,确实需要先掌握 __init____new____call__ 这三个方法的作用和调用顺序。如有需要,读者可跳转下方链接学习:
python中的__init__、newcall-CSDN博客

正文开始:

在Python中,单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。

一、使用装饰器实现单例

原理 :通过装饰器控制类的实例化过程,确保仅生成一个实例。
步骤

  1. 定义一个装饰器函数。

  2. 在装饰器中管理实例的创建和返回。

代码示例

复制代码
def singleton_decorator(cls):
    print("装饰器执行(类定义时立即执行)")
    instances = {}

    def get_instance(*args, **kwargs):
        print("调用 get_instance()(实例化时执行)")
        if cls not in instances:        # 单例模式的关键点就在这里
            print("创建新实例")
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance


@singleton_decorator
class SingletonClass:
    def __init__(self):
        print("调用 __init__()")
        self.data = "Singleton Data"


# 测试
print("开始实例化")
a = SingletonClass()
print("------------")
b = SingletonClass()
print(a is b)  # 输出:True


# 装饰器执行(类定义时立即执行)
# 开始实例化
# 调用 get_instance()(实例化时执行)
# 创建新实例
# 调用 __init__()
# ------------
# 调用 get_instance()(实例化时执行)
# True

二、元类实现单例重写__call__

原理 :通过元类的 __call__ 方法控制实例创建流程。
步骤

  1. 定义一个元类,重写 __call__ 方法。

  2. 在元类中检查是否已存在实例。

代码示例

复制代码
class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        print("调用 __call__()")
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]


class SingletonClass(metaclass=SingletonMeta):
    def __init__(self):
        print("调用 __init__()")
        self.data = "Singleton Data"


# 测试
a = SingletonClass()
b = SingletonClass()
print(a is b)  # 输出:True

# 调用 __call__()
# 调用 __init__()
# 调用 __call__()
# True

三、重写 __new__

原理 :通过重写类的 __new__ 方法,直接控制实例创建。
步骤

  1. 在类中定义类变量存储实例。

2.在 __new__ 方法中返回已有实例或创建新实例。

代码示例

复制代码
class SingletonClass:
    _instance = None

    def __new__(cls, *args, **kwargs):
        print("__new__")
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        print("__init__")
        self.data = "Singleton Data"


# 测试
a = SingletonClass()
b = SingletonClass()
print(a is b)  # 输出:True

# __new__
# __init__
# __new__
# __init__
# True

四、线程安全的单例模式

问题 :上述方法在并发环境下可能创建多个实例。
解决方案 :加锁(如 threading.Lock)确保线程安全。

代码示例(元类 + 线程安全)​

复制代码
import threading


class SingletonMeta(type):
    """
    单例模式的元类实现。
    控制类的实例化过程,确保线程安全且唯一实例。
    """
    _instances = {}  # 保存所有单例类的实例(键是类,值是实例)
    _lock = threading.Lock()  # 线程锁

    def __call__(cls, *args, **kwargs):
        # 第一次检查:避免已存在实例时不必要的加锁
        if cls not in cls._instances:
            # 加锁确保线程安全
            with cls._lock:
                # 第二次检查:防止其他线程已创建实例
                if cls not in cls._instances:
                    # 创建实例并保存
                    instance = super().__call__(*args, **kwargs)
                    cls._instances[cls] = instance
        # 返回已存在的实例
        return cls._instances[cls]


class Singleton(metaclass=SingletonMeta):
    """
    单例类示例。
    通过元类 SingletonMeta 控制实例唯一性。
    """
    def __init__(self):
        # 初始化代码(只会执行一次)
        self._data = "单例数据"
        print("Singleton 初始化完成")


# 测试多线程环境下的单例行为
def create_singleton():
    obj = Singleton()
    print(id(obj))

if __name__ == "__main__":
    threads = []
    for _ in range(5):
        t = threading.Thread(target=create_singleton)
        threads.append(t)
        t.start()

    for t in threads:
        t.join()

# Singleton 初始化完成
# 1807031580512
# 1807031580512
# 1807031580512
# 1807031580512
# 1807031580512
相关推荐
爬虫程序猿4 分钟前
利用 Java 爬虫获取淘宝商品 SKU 详细信息实战指南
java·开发语言·爬虫
F2E_Zhangmo8 分钟前
基于cornerstone3D的dicom影像浏览器 第五章 在Displayer四个角落显示信息
开发语言·前端·javascript
He19550125 分钟前
Go初级之十:错误处理与程序健壮性
开发语言·python·golang
m0_738120721 小时前
CTFshow系列——PHP特性Web93-96
开发语言·安全·web安全·php·ctfshow
m0_570466411 小时前
代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
java·开发语言·算法
程序喵大人1 小时前
分享个C++线程池的实现源码
开发语言·c++·线程池
和鲸社区1 小时前
《斯坦福CS336》作业1开源,从0手搓大模型|代码复现+免环境配置
人工智能·python·深度学习·计算机视觉·语言模型·自然语言处理·nlp
不会吃萝卜的兔子1 小时前
go webrtc - 1 go基本概念
开发语言·golang·webrtc
豌豆花下猫2 小时前
Python 潮流周刊#118:Python 异步为何不够流行?(摘要)
后端·python·ai
THMAIL2 小时前
深度学习从入门到精通 - LSTM与GRU深度剖析:破解长序列记忆遗忘困境
人工智能·python·深度学习·算法·机器学习·逻辑回归·lstm