通过其对象和参数实例化 class 的单例

Singleton that instantiates a class by its object and arguments

我正在尝试准备一个单例 class,它不仅可以通过 class 类型来区分实例,还可以通过调用 class 的参数来区分实例。

假设我有一个单身人士 class,如下所示:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

现在我正在尝试创建两个具有不同参数的 class 实例:

class MyClass(metaclass=Singleton):
    def __init__(self, x, y):
        print(f"Called constructor with x as {x} and y as {y}")

a = MyClass(1, 2)
b = MyClass(1, 2)
print(id(a) == id(b))  # Returns True, which is fine


c = MyClass(1, 3)
d = MyClass(1, 2)
print(id(c) == id(d))  # Returns True, which is not really fine to me :)
                       # Moreover y in that case is 3, not 2.

如果我想通过初始化 class 的参数来区分单例中的实例怎么办?

以下是对我有用的方法:

from dataclasses import dataclass

@dataclass(frozen=True)
class ObjectKey:
    obj_type: object
    args: tuple
    kwargs: frozenset

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        obj_key = ObjectKey(obj_type=cls, args=args, kwargs=frozenset(kwargs.items()))
        if obj_key not in cls._instances:
            cls._instances[obj_key] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[obj_key]