在 Python 里,单例模式指的是一个类仅有一个实例,并且提供一个全局访问点来获取该实例。下面为你介绍几种实现单例模式的常见方法。
1. 使用模块
在 Python 里,模块天然就是单例模式。当模块被导入时,Python 会对其进行一次加载和执行,之后再导入相同模块时,会直接使用之前已经加载的模块对象。
# singleton.py
class Singleton:def __init__(self):self.value = Nonedef set_value(self, value):self.value = valuedef get_value(self):return self.valuesingleton_instance = Singleton()
在其他文件中使用该单例:
# main.py
from singleton import singleton_instancesingleton_instance.set_value(42)
print(singleton_instance.get_value())
这种方式简单直接,不过它将单例的实例化过程放在了模块级别,可能会让代码的结构和意图不够清晰。
2. 使用装饰器
借助装饰器可以把一个类变成单例模式,以下是实现代码:
def singleton(cls):instances = {}def wrapper(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return wrapper@singleton
class MySingleton:def __init__(self):pass# 使用单例类
s1 = MySingleton()
s2 = MySingleton()
print(s1 is s2)
在上述代码中,singleton
装饰器内部维护了一个字典 instances
,用于存储每个类的单例实例。当调用被装饰的类来创建实例时,会先检查该类是否已经有实例存在,如果没有则创建一个新实例并存储在字典中,否则直接返回已有的实例。
3. 使用元类
元类是创建类的类,通过自定义元类可以实现单例模式:
class SingletonMeta(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:cls._instances[cls] = super().__call__(*args, **kwargs)return cls._instances[cls]class MySingleton(metaclass=SingletonMeta):def __init__(self):pass# 使用单例类
s1 = MySingleton()
s2 = MySingleton()
print(s1 is s2)
这里定义了一个元类 SingletonMeta
,在元类的 __call__
方法中实现了单例的逻辑。当使用该元类创建类时,每次实例化该类都会返回同一个实例。
4. 基于 __new__
方法
在类的 __new__
方法中实现单例逻辑:
class MySingleton:_instance = Nonedef __new__(cls, *args, **kwargs):if not cls._instance:cls._instance = super().__new__(cls)return cls._instancedef __init__(self):pass# 使用单例类
s1 = MySingleton()
s2 = MySingleton()
print(s1 is s2)
__new__
方法是在实例创建之前被调用的,在这个方法里检查类的 _instance
属性是否已经存在实例,如果不存在则创建一个新实例并赋值给 _instance
,否则直接返回已有的实例。
这些方法各有优劣,你可以根据具体需求来选择合适的实现方式。