Reputation: 144
I have a python class, let's call it C. it takes a string in it's constructor. how could i make sure (design-wise) that
x = C('a')
y = C('b')
z = C('a')
this configuration leads to x and y pointing to different places, and x and z pointing to the same place? meaning
x is y == False
x is z == True
Upvotes: 2
Views: 394
Reputation: 82899
One lazy way to do this would be to annotate the class itself with functools.lru_cache
:
from functools import lru_cache
@lru_cache(None)
class C:
def __init__(self, val):
self.val = val
x = C('a')
y = C('b')
z = C('a')
print(x is y) # False
print(x is z) # True
lru_cache
is actually intended for caching functions, but it works with any callable, including classes, where it caches the call to C.__init__
. Parameters must be hashable, of course.
This way, as far as I know, instances are not garbage-collected even if they are no longer used, but you could control the maximum number of instances to cache with the parameter to lru_cache
(None
meaning "no limit"), which might be good enough for many cases.
Upvotes: 1
Reputation: 32244
You can use a WeakValueDictionary to keep all existing instances of your class in a dict like object on the class. In the __new__
method you look up the existing object in the dict and if it exists return it, if not create a new instance and save it to the dict
from weakref import WeakValueDictionary
class C:
__instances = WeakValueDictionary()
def __new__(cls, value):
obj = cls.__instances.get(value)
if not obj:
obj = object.__new__(cls)
cls.__instances[value] = obj
return obj
def __init__(self, value):
self.value = value
We use weak references to the instances so that they can be garbage collected when nothing else references them.
Upvotes: 2