单例模式Singleton和Python实现, 2026-03-29

(2026.03.29 Sun)
Singleton单例模式指的是一个类只有一个实例对象。本文测试环境python 3.13.5。

在Python中,最常见的单例模式是None对象。

Python中常见的实现单例模式的方法如下:

  • module引用实现
  • 覆盖构造函数
  • 单例装饰器
  • 从元类metaclass创建

此外,还有线程安全的创建方法。

module引用实现

从一个单独文件/module中引入某个类,是最简单常见的设置单例模式的方法。

# config.py
class AppConfig:
    def __init__(self):
        self.value_a = 1
        self.value_b = 2
# main.py
from config import AppConfig

if __name__ == "__main__":
    a = AppConfig()
    print(a.value_a)

覆盖构造函数Override construction function __new__

在创建类时,重写构造函数__new__,检测是否已经创建实例。如果没有创建,则新创建并记录;如果已经创建,则返回已经创建的实例。

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

在类Singleton中,设置一个类变量_instance。该变量因其代表了类的特性,无法被实例修改,也不能在类方法和实例方法中改动,仅仅在构造函数中检测和修改。

注意,在构造函数__new__中,传入的类本身cls而非实例本身self

原因:在实例化过程中,首先运行构造函数__new__,再运行初始化函数__init__默认情况下,Python类的构造函数__new__返回当前类的一个实例对象。第一次实例化时,运行构造函数检测到类变量cls._instance为空,则调用object类的__new__方法创建一个实例对象,并赋给cls._instance。而从第二次实例化开始,因cls._instance,构造函数直接返回被cls._instance保存的实例对象本身。这个过程保证了每个实例化对象都是第一次实例化的对象。

接下来实例化并测试

a = Singleton()
b = Singleton()
a is b
>> True

两次实例化的对方分别是ab,比较这两个对象时需要比较其内存地址,因此使用a is b语句判断而非a is b指令判断。

单例装饰器 singleton decorator

设置一个单例装饰器,其中包含一个字典,用于记录不同类的首次实例化instance。

def singleton(cls):
    instances = {}  # 用于保存实例
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

该装饰器中,将实例化的对象保存在instances中,并如果检测到则不再为该类创建实例。

@singleton
class ClassA:
    pass
>> a = ClassA()
>> b = ClassA()
>> a is b
True

从metaclass创建

class SingletonMeta(type):
    _instances = {}

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

class Singleton(metaclass=SingletonMeta):
    pass

s1 = Singleton()
s2 = Singleton()

print(s1 is s2)  # Output: True

Thread-safe singleton线程安全的单例模式

在多线程环境下,上面的单例模式方法有潜在的隐患,即当多个线程同时创建一个对象时,可能导致单例类创建多个实例对象,这将失去单例模式的价值和意义。加入线程锁thread lock可解决该问题。

import threading

class ThreadSafeSingleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                # Double-check pattern
                if cls._instance is None:
                    print(f"Thread {threading.current_thread().name}: Creating instance")
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if not self._initialized:
            with self._lock:
                if not self._initialized:
                    print(f"Thread {threading.current_thread().name}: Initializing")
                    self.data = {}
                    self._initialized = True

Reference

  1. freecodecamp, Bala Priya C, How to Build a Singleton in Python (and Why You Probably Shouldn't)
  2. stackabuse, Scottish Robinson, Creating a Singleton in Python
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容