67 lines
1.7 KiB
Python
67 lines
1.7 KiB
Python
import threading
|
|||
|
|
from dataclasses import dataclass
|
||
|
|
|
||
|
|
|
||
|
|
class ParameterizedSingletonMeta(type):
|
||
|
|
"""
|
||
|
|
参数化单例元类
|
||
|
|
行为:
|
||
|
|
- 相同 (类, args, kwargs) → 同一实例
|
||
|
|
- 不同参数 → 不同实例
|
||
|
|
"""
|
||
|
|
|
||
|
|
_instances: dict = {}
|
||
|
|
_lock = threading.RLock()
|
||
|
|
|
||
|
|
def __call__(cls, *args, **kwargs):
|
||
|
|
# 1. kwargs 排序,保证顺序无关
|
||
|
|
kwargs_key = tuple(sorted(kwargs.items()))
|
||
|
|
|
||
|
|
# 2. 构造不可变的 key
|
||
|
|
key = (cls, args, kwargs_key)
|
||
|
|
|
||
|
|
# 3. 防御:确保所有参数都可 hash
|
||
|
|
try:
|
||
|
|
hash(key)
|
||
|
|
except TypeError as e:
|
||
|
|
raise ValueError(
|
||
|
|
f"{cls.__name__} 的单例参数必须全部可 hash"
|
||
|
|
) from e
|
||
|
|
|
||
|
|
with cls._lock:
|
||
|
|
if key not in cls._instances:
|
||
|
|
cls._instances[key] = super().__call__(*args, **kwargs)
|
||
|
|
else:
|
||
|
|
print(f"[HIT] 命中缓存实例: {key}")
|
||
|
|
|
||
|
|
return cls._instances[key]
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def get_all_instances(cls):
|
||
|
|
"""调试用:返回当前已创建的所有实例"""
|
||
|
|
return list(cls._instances.values())
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class Demo(metaclass=ParameterizedSingletonMeta):
|
||
|
|
"""
|
||
|
|
示例:参数化单例对象
|
||
|
|
"""
|
||
|
|
|
||
|
|
name: str
|
||
|
|
|
||
|
|
def __post_init__(self):
|
||
|
|
print(f"正在初始化 Demo(name={self.name})")
|
||
|
|
|
||
|
|
def __str__(self):
|
||
|
|
return f"<Demo name={self.name} id={id(self)}>"
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
print("=== 测试 1:相同参数 ===")
|
||
|
|
d1 = Demo(name="config_A")
|
||
|
|
d2 = Demo(name="config_A")
|
||
|
|
print(d1)
|
||
|
|
print(d2)
|
||
|
|
print("是否同一实例:", d1 is d2)
|
||
|
|
print(ParameterizedSingletonMeta.get_all_instances())
|