Singleton metaclass for each argument set compatible with Pickle I am creating a metaclass which ensures that instances of an actual class A are kind of singletons. But rather than having only single instance of A, I would like to have one instance per argument set given to A.
That is
class A(metaclass=ArgumentSingleton):
    pass

r = A()
s = A()
t = A(1)
u = A(1)
v = A('hi')

print(r is s)  # True
print(r is t)  # False
print(t is u)  # True
print(v is u)  # False
print(v is r)  # False

Moreover, the property of 'being a singleton' must survive pickling.
That is
a = A()

with open('tmp.pkl', 'wb') as f:
    pkl.dump(a, f)

with open('tmp.pkl', 'rb') as f:
    b = pkl.load(f)

print(a is b)  # True

For example Sympy is capable of doing that with their constants (such as pi) and I tried similar approach.
class ArgumentSingleton(type):
    _instances = {}

    def __new__(cls, name, bases, class_dict):
        def __init__(self, *args):
            self._args = args
            print('Here in __init__')

        def __reduce_ex__(self, protocol):
            return type(self), (*self._args,)

        init = '__init__'
        reduce = '__reduce_ex__'
        method_absence = [
            init not in class_dict,
            reduce not in class_dict
        ]

        if all(method_absence):
            class_dict[init] = __init__
            class_dict[reduce] = __reduce_ex__
        elif any(method_absence):
            raise ArgumentSingletonException(
                f&quot;Either both methods '{init}', '{reduce}' are defined or &quot;
                f&quot;none of them in class: {name}&quot;
            )

        new_class = super().__new__(cls, name, bases, class_dict)

        return new_class

    def __call__(cls, *args, **kwargs):
        key = (cls, *args, *kwargs.items())
        if key not in ArgumentSingleton._instances:
            ArgumentSingleton._instances[key] = super().__call__(*args, **kwargs)
        return cls._instances[key]


The code depends quite deeply (at least to my standards) on inner workings of Python and I am afraid of any hidden bugs and hidden problems.
The purpose of controling presence of __init__ and __reduce_ex__ is to explicitly move responsibility for __reduce_ex__ to the creators of the class A in case they decide to provide their __init__.
Any comments or suggestions appreciated!
So far, I am aware of the fact that the arguments must be hashable. That is not problem for me, as this construction is meant to speed up comparison of my complex hashable objects.
The point of having to define either neither or both of __init__ and __reduce_ex__ is to set _args.
However you can just set _args in __call__ and then use the one you've set in your __reduce_ex__.
Note: untested
class ArgumentSingleton(type):
    __INSTANCES = {}

    def __new__(cls, name, bases, class_dict):
        def __reduce_ex__(self, protocol):
            return partial(type(self), *self.__args, **self.__kwargs), ()

        def __init__(self, *args, **kwargs):
            pass

        class_dict.setdefault('__init__', __init__)
        class_dict.setdefault('__reduce_ex__', __reduce_ex__)
        return super().__new__(cls, name, bases, class_dict)

    def __call__(cls, *args, **kwargs):
        key = (cls, args, frozendict(kwargs))
        if None is (self := cls.__INSTANCES.get(key)):
            self = cls.__INSTANCES[key] = super().__call__(cls, *args, **kwargs)
            self.__args, self.__kwargs = key[1:]
        return self

Now we should be able to see we can just stop defining a metaclass by;

changing __call__ to __new__, and
defining a default __reduce_ex__ on the base class.

from frozendict import frozendict
from functools import partial

class Singleton:
    __INSTANCES = {}

    def __new__(cls, *args, **kwargs):
        key = (cls, args, frozendict(kwargs))
        if None is (self := cls.__INSTANCES.get(key)):
            self = cls.__INSTANCES[key] = super().__new__(cls)
            self.__args, self.__kwargs = key[1:]
        return self

    def __reduce_ex__(self, protocol: int):
        return partial(type(self), *self.__args, **self.__kwargs), ()

class A(Singleton):
    pass


# passes all your tests and the following one
a = A(&quot;hi&quot;)
b = pickle.loads(pickle.dumps(a))
assert a is b