理解单例模式之前,确实必要先掌握 __init__、__new__ 和 __call__ 这三个方法的作用和调用序次。如有必要,读者可跳转下方链接学习:
python中的__init__、__new__、__call__-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
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |