python的单例模式
1、单例模式的应用场景
资源共享:当多个对象需要共享同一个资源时,可以使用单例模式来管理该资源的访问。例如,数据库连接池、日志记录器等。
配置信息:当需要在应用程序中共享配置信息时,可以使用单例模式来保存和访问配置对象。这样可以确保配置信息的一致性和全局可访问性。
缓存管理:在需要缓存数据的场景中,可以使用单例模式来管理缓存对象。这样可以避免重复创建缓存对象,提高性能和资源利用率。
对话框或窗口管理:在图形用户界面(GUI)应用程序中,可以使用单例模式来管理对话框或窗口对象。这样可以确保只有一个实例对象存在,并且可以方便地进行访问和控制。
日志记录:在需要记录应用程序日志的场景中,可以使用单例模式来管理日志记录器对象。这样可以确保只有一个日志记录器实例,并且可以在整个应用程序中方便地使用。
2、当一个类定义被执行时,将发生以下步骤:
- 解析 MRO 条目
- 确定适当的元类
- 准备类命名空间
- 执行类主体
- 创建类对象
参考:https://docs.python.org/zh-cn/3.7/reference/datamodel.html#customizing-class-creation
3、__new__
调用以创建一个 cls 类的新实例。
__new__() 是一个静态方法 (因为是特例所以你不需要显式地声明),它会将所请求实例所属的类作为第一个参数。其余的参数会被传递给对象构造器表达式 (对类的调用)。__new__() 的返回值应为新对象实例 (通常是 cls 的实例)。
如果 __new__() 返回一个 cls 的实例,则新实例的 __init__() 方法会在之后被执行,例如 __init__(self[, ...]),其中 self 为新实例,其余的参数与被传递给 __new__() 的相同。
如果 __new__() 未返回一个 cls 的实例,则新实例的 __init__() 方法就不会被执行。
4、__init__
在实例 (通过 __new__()) 被创建之后,返回调用者之前调用。其参数与传递给类构造器表达式的参数相同。一个基类如果有 __init__() 方法,则其所派生的类如果也有 __init__() 方法,就必须显式地调用它以确保实例基类部分的正确初始化;例如: super().__init__([args...]).
因为对象是由 __new__() 和 __init__() 协作构造完成的 (由 __new__() 创建,并由 __init__() 定制),所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError。
5、非线程安全的单例模式
import time class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: time.sleep(1) cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance #instance1 = Singleton() #instance2 = Singleton() #print(instance1 is instance2) # 输出: True import threading def create_singleton(): instance = Singleton() print(instance) threads = [] for _ in range(10): t = threading.Thread(target=create_singleton) threads.append(t) t.start() for t in threads: t.join() <__main__.Singleton object at 0x7f8269c91f60> <__main__.Singleton object at 0x7f8269c91000> <__main__.Singleton object at 0x7f8269c90df0> <__main__.Singleton object at 0x7f8269c90be0> <__main__.Singleton object at 0x7f8269c909d0> <__main__.Singleton object at 0x7f8269c907c0> <__main__.Singleton object at 0x7f8269c905b0> <__main__.Singleton object at 0x7f8269c903a0> <__main__.Singleton object at 0x7f8269c90190> <__main__.Singleton object at 0x7f8269c91d20>
6、线程安全的单例模式
import threading class Singleton: _instance = None _lock = threading.Lock() def __new__(cls, *args, **kwargs): thread_id = threading.current_thread() if not cls._instance: print("我再等待着", thread_id) with cls._lock: print("我进来了",thread_id) if not cls._instance: cls._instance = super().__new__(cls, *args, **kwargs) print("我直接返回了", thread_id) return cls._instance def create_singleton(): instance = Singleton() print(instance) threads = [] for _ in range(10): t = threading.Thread(target=create_singleton) threads.append(t) t.start() for t in threads: t.join() 我再等待着 <Thread(Thread-1 (create_singleton), started 139852282197760)> 我进来了 <Thread(Thread-1 (create_singleton), started 139852282197760)> 我直接返回了 <Thread(Thread-1 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-2 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-3 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-4 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-5 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-6 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-7 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-8 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-9 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0> 我直接返回了 <Thread(Thread-10 (create_singleton), started 139852282197760)> <__main__.Singleton object at 0x7f31e59b90c0>
参考:
https://docs.python.org/zh-cn/3.7/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement
https://docs.python.org/zh-cn/3.7/library/threading.html#lock-objects