Python 单例模式(Singleton)知识点汇总

一、单例模式核心概念

1. 定义

单例模式是一种创建型设计模式,保证一个类在整个程序中只能创建唯一的一个实例,无论实例化多少次,都返回同一个对象。

2. 核心特点

  • 只能有一个实例
  • 全局共享同一个对象,节省内存资源
  • 适用于:日志工具、数据库连接、配置管理、线程池等场景

3. 使用场景

  • 全局配置类(整个程序共用一套配置)
  • 数据库连接池(避免重复创建连接)
  • 日志记录器(统一写入日志文件)
  • 打印机/硬件控制(避免多对象冲突)

二、Python 实现单例的 5 种常用方法

方法1:使用 __new__ 方法(最常用、推荐)

利用 Python 实例化时先调用 __new__ 创建对象,再调用 __init__ 初始化的特性,控制实例创建。

class Singleton:
    # 存储唯一实例
    _instance = None

    def __new__(cls, *args, **kwargs):
        # 第一次创建才分配内存
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

# 测试
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True,同一个对象

方法2:使用装饰器(简洁优雅)

用装饰器包装类,自动实现单例,不侵入类内部代码。

def singleton(cls):
    _instance = {}
    def wrapper(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)
        return _instance[cls]
    return wrapper

@singleton
class Test:
    pass

t1 = Test()
t2 = Test()
print(t1 is t2)  # True

方法3:使用模块(Python 天然单例)

Python 模块本身就是单例,模块只会被加载一次,全局共用。

  1. 创建 config.py
class Config:
    pass

# 创建唯一实例
config = Config()
  1. 使用
from config import config

方法4:使用类方法(手动控制)

自定义获取实例的方法,禁止直接实例化。

class Singleton:
    _instance = None

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

# 只能用这个方法获取实例
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()

方法5:使用元类 metaclass(高级)

通过元类控制类的创建行为,底层实现单例。

class SingletonMeta(type):
    _instance = None
    def __call__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

class Test(metaclass=SingletonMeta):
    pass

三、带初始化参数的单例(解决 __init__ 重复执行)

默认 __new__ 单例会重复执行 __init__,用以下方式修复:

class Singleton:
    _instance = None
    _initialized = False  # 标记是否初始化过

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

    def __init__(self, name):
        # 只初始化一次
        if not self._initialized:
            self.name = name
            self._initialized = True

# 测试
s1 = Singleton("张三")
s2 = Singleton("李四")
print(s1.name)  # 张三(不会被覆盖)
print(s1 is s2) # True

四、线程安全的单例(多线程必备)

以上方法在多线程下不安全,可能创建多个实例,需加锁:

import threading

class ThreadSingleton:
    _instance = None
    _lock = threading.Lock()  # 线程锁

    def __new__(cls, *args, **kwargs):
        # 加锁保证同一时间只有一个线程创建实例
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
        return cls._instance

五、单例模式优缺点

✅ 优点

  1. 内存中只有一个对象,节省内存
  2. 避免频繁创建/销毁对象,提升性能
  3. 全局统一访问,方便管理共享资源

❌ 缺点

  1. 扩展困难,违背开闭原则
  2. 单例职责过多,违背单一职责原则
  3. 单元测试困难(无法 mock 独立对象)

六、Python 单例使用总结

  1. 首选 __new__ 方法:简单通用,适合大多数场景
  2. 简洁用装饰器:代码优雅,不修改类结构
  3. 极简用模块:Python 天然支持,零代码实现
  4. 多线程必须加锁:保证线程安全
  5. 带参数必须控制初始化:避免 __init__ 重复执行

七、最佳实践代码

# 通用、线程安全、带参数、只初始化一次的单例
import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()
    _initialized = False

    def __new__(cls, *args, **kwargs):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, *args, **kwargs):
        if not self._initialized:
            # 初始化代码写这里
            self.config = args
            self._initialized = True

# 使用
if __name__ == '__main__':
    a = Singleton("test")
    b = Singleton("dev")
    print(a is b)  # True

总结

  1. 单例 = 一个类永远只有一个对象
  2. Python 最常用:__new__ 实现、装饰器、模块
  3. 多线程必须加线程锁
  4. 带参数单例要防止 __init__ 重复初始化
  5. 适合全局唯一资源:配置、数据库连接、日志

更多推荐