单例模式是设计模式的一种,确保一个类只有一个实例,并提供一个全局访问点。在开发中需要某个类只能有一个实例,比如配置管理、数据库连接池、日志记录之类的场景。
1. 使用模块天然的单例特性
Python 的模块在第一次导入时会执行代码生成对象,之后的导入直接引用已存在的对象,天然支持单例模式。
# singleton.py
class SingletonClass:
def __init__(self):
self.value = "单例实例"
singleton_instance = SingletonClass()
# test.py:
from singleton import singleton_instance
print(singleton_instance.value) # 输出:单例实例
优点:简单、线程安全。
缺点:不够灵活,无法延迟初始化。
2. 使用装饰器
通过装饰器控制类的实例化逻辑,确保只创建一个实例。
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class MyClass:
def __init__(self, name):
self.name = name
# 测试
a = MyClass("实例1")
b = MyClass("实例2")
print(a is b) # 输出:True
print(a.name) # 输出:实例1(后续初始化参数会被忽略)
优点:代码复用性强,可应用于多个类。
缺点:线程不安全(多线程环境下可能重复创建实例)。如果加锁,则所有被装饰类共享同一个锁对象(不同类的实例化也会互相阻塞)
3. 重写类的 __new__ 方法
通过覆盖类的 __new__ 方法,控制实例的创建过程。
import threading
class ThreadSafeSingleton:
_instance = None
_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not cls._instance:
with cls._lock:
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
# 测试
def create_singleton():
obj = ThreadSafeSingleton()
print(id(obj))
threads = [threading.Thread(target=create_singleton) for _ in range(10)]
for t in threads:
t.start()
缺点:__init__会重复执行初始化,可能导致属性被覆盖
- 使用元类(Metaclass):通过自定义元类,拦截类的实例化过程。