Home > Back-end >  Python Singleton objects with the same attribute should reference to the same object
Python Singleton objects with the same attribute should reference to the same object

Time:02-13

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?

CodePudding user response:

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

CodePudding user response:

The following are two ways by using __new__, decorator to create a singleton class in Python.

  1. overriding the __new__ method
class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    a = 1

one = MyClass()
two = MyClass()

two.a = 5
print(one.a)
#5
print(id(one))
#139889931666384
print(id(two))
#139889931666384
print(one == two)
#True
print(one is two)
#True
  1. Using python decorator
def singleton(cls, *args, **kw):
        instances = {}
        def _singleton(*args, **kw):
           if cls not in instances:
                instances[cls] = cls(*args, **kw)
           return instances[cls]
        return _singleton
        
@singleton
class MyClass(object):
    a = 1
    def __init__(self, x=0):
        self.x = x

one = MyClass()
two = MyClass()

two.a = 3
print(one.a)
#3
print(id(one))
#139944257532352
print(id(two))
#139944257532352
print(one == two)
#True
print(one is two)
#True
one.x = 1
print(one.x)
#1
print(two.x)
#1
  • Related