I am working with Python code that calls into C wrappers, but the C code is very buggy (and I have no other alternative) and causes a segfault when a Python object managed in C goes out of scope, so I have to keep references to each object created.
Is there any good way to make an ergonomic "unique" wrapper where each class can only have one instance per set of constructor arguments, e.g.
@unique
class Test:
cls_val = 0
def __init__(self, val):
self.val = val
a = Test(1)
b = Test(1)
assert a is b
c = Test(2)
d = Test(2)
assert c is not b and c is not a
assert c is d
I've made this decorator, but it prevents any @unique-decorated class from being used as a base class (constructing an instance of the derived class calls the __new__
of the decorator).
def unique(unique_cls):
class Unique:
instances = {}
unique_class = unique_cls
def __new__(cls, *args, **kwargs):
if not Unique.instances.get(
(
cls.unique_class,
f_args := frozenset(args),
f_kwargs := frozenset(kwargs),
)
):
Unique.instances[
(Unique.unique_class, f_args, f_kwargs)
] = Unique.unique_class(*args, **kwargs)
return Unique.instances[(Unique.unique_class, f_args, f_kwargs)]
def __getattr__(self, name):
# Overloaded to get class attributes working for decorated classes
return object.__getattribute__(Unique.unique_class, name)
return Unique