Search code examples
pythonpython-3.xcachingclass-variables

How do I pass the same variable(iterable) between instances of different classes(that inherits from the same parent)


I want to pass a variable(iterable )between instances of different classes. I have a structure similar with the one below.

Each class has its own module(so no globals) and needs to work in python 3 and 2.

class O:
    pass


class A(O):
    pass


class B(O):

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


class B1(B):

    def p(self):
        self.cache.add_to_cache("32", "something something")


class B2(B):

    def p(self):
        self.cache.get_from_cache("52",  "something else")

For B and its sub-classes I want to create a cache. All instances of this classes(B, B1, B2) to use the same cache.

To keep it simple, let's say that the cache is just a dict.

c = {}

a = A(c)
b1 = B() - needs c
b1.p()
b2 = C() - needs c
b2.p()

print(cache) 

Off course the example above, is wrong because the cache is different for each instance.

The chache should be :

{
"32", "something something"
"52":  "something else"
}

Solution

  • Another approach to this is using CacheService as an injectable Singleton service, which I consider a better practice.
    Read this first for a code/syntax solution to your direct question, or continue reading for a solution with better design.

    class O(object):
        pass
    
    class CacheService(object):
        __instances = {}
    
        @staticmethod
        def getinstance(owner_id):
            if owner_id not in CacheService.__instances:
                CacheService.__instances[owner_id] = CacheService(owner_id)
            return CacheService.__instances[owner_id]
    
        def __init__(self, owner_id):
            self._owner_id = owner_id
            self._owner_query = CacheService.__name__ + self._owner_id
            self._cache = {}
    
        def put_in_cache(self, key, value):
            self._cache[self._owner_query + str(key)] = value
    
        def get_from_cache(self, key):
            return self._cache.get(self._owner_query + str(key), "the_default")
    
    
    class B(O):
        def __init__(self):
            self._cache = CacheService.getinstance(B.__name__)
    
    class B1(B):
        def __init__(self):
            super(B1, self).__init__()
    
        def p(self):
            val1 = self._cache.get_from_cache("a")
            print(val1)
    
    
    class B2(B):
        def __init__(self):
            super(B2, self).__init__()
    
        def p(self):
            self._cache.put_in_cache("a", 2)
    
    if __name__ == "__main__":
        b1 = B1()
        b2 = B2()
    
        b2.p()
        b1.p()
    

    out:

    2


    This still uses a class variable, but hides it from your "everyday code", and moves it to the "infrastructure level".
    I see this as cleaner, as now your class hierarchy shouldn't handle its own global variables.