1

I want Python to return the same object when the instances are created with the similar attributes. Also when I am changing some attribute of one instance, that attribute should be synchronized between other instances also.

class Session:
    def __init__(self, id):
        self.id = id 
        self.data = None

session1 = Session(1)
session1.data = 202
print(session1.data) # 202
print(id(session1)) # should be 1111

session11 = Session(1)
print(session11.data) # 202
print(id(session11)) # should be the same as session1 -> 1111

session2 = Session(2)
print(id(session2)) # 2222

You can see above that I want session1 and session1a be the same object because of Session(1), while session2 is another object because of Session(2).

How could I do it?

Rustam-Z
  • 113
  • 1
  • 9
  • Note that this may be unexpected behavior, as objects don’t usually behave this way. At least using an explicit alternative constructor would make this clearer, e.g.: `Session.singleton(1)`. Also note that this behavior prevents garbage collecting objects if you need to keep them around… – deceze Feb 13 '22 at 12:41
  • Does this answer your question? [Creating a singleton in Python](https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python) – aaossa Feb 13 '22 at 12:42
  • @aaossa I have read that article but could not found an answer – Rustam-Z Feb 13 '22 at 12:53
  • @deceze I didn't understand what you mean by `Session.singleton(1)` – Rustam-Z Feb 13 '22 at 12:54

1 Answers1

1

You can override the __new__ method to return a cached object for the same parameters.

A weakref.WeakValueDictionary is an appropriate data structure for storing your cached objects, when objects are deleted they will be garbage collected rather than persisting because your cache references them

from weakref import WeakValueDictionary


class Session:

    _cache = WeakValueDictionary()

    def __new__(cls, id):
        obj = cls._cache.get(id)
        if not obj:
            obj = object.__new__(cls)
            cls._cache[id] = obj
        return obj

    def __init__(self, id):
        self.id = id

The same object will be returned for the same id

s1 = Session(1)
print(id(s1))  # 4532746224
s2 = Session(1)
print(id(s2))  # 4532746224
s3 = Session(2)
print(id(s3))  # 4534405248
Iain Shelvington
  • 31,030
  • 3
  • 31
  • 50
  • Sorry, after some tries I have noticed that it is not working, when I am changing some attribute of one class, that attribute is not being sync – Rustam-Z Feb 13 '22 at 13:04
  • How are you changing the attribute of an object where it's not working, can you add an example to the question? A quick bit of testing using my example and when I add/change an attribute on `s1` it is reflected on `s2` – Iain Shelvington Feb 13 '22 at 13:08
  • I have added, check it out now – Rustam-Z Feb 13 '22 at 13:08
  • Yes I understand what you did. First of all change the attribute, then create a new instance, then check if they have the same values for attributes. They DON'T – Rustam-Z Feb 13 '22 at 13:22
  • 1
    @Rustam-Z I see what you mean, unfortunately the `__init__` method gets called every time even when returning the same object, and in your `__init__` method data gets set to None. There is probably a way to skip the `__init__` method but a bit of a hacky work around could be to use `self.data = getattr(self, 'data', None)` in your `__init__` method – Iain Shelvington Feb 13 '22 at 13:26
  • `self.data = getattr(self, 'data', None)` works fine, thank you Iain! – Rustam-Z Feb 13 '22 at 13:32
  • Can we achieve it using python decorator? https://stackoverflow.com/questions/71103429/multiple-python-singleton-class-objects-with-the-same-attribute-should-reference – Shubhank Gupta Feb 13 '22 at 18:11