1

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"
}
Gulzar
  • 23,452
  • 27
  • 113
  • 201
user3541631
  • 3,686
  • 8
  • 48
  • 115

2 Answers2

1

To directly answer the programming question, Use class variables.

As a side note, it would be much better to use some kind of "CacheService" and inject that to the constructor, rather than use inheritance and class variables.
For this, see my other answer.


Code for using class variables follows:

class O(object):
    pass

class B(O):
    __cache = {}  # use your cache class if you want, I am using dict just for show
    def __init__(self):
        pass

    def _get_from_cache(self, key):
        return self._cache.get(key, "default1")

    def _put_in_cache(self, key, value):
        self._cache[key] = value


class B1(B):
    def __init__(self):
        super(B1, self).__init__()

    def p(self):
        val1 = self._get_from_cache("a")
        print(val1)


class B2(B):
    def __init__(self):
        super(B2, self).__init__()

    def p(self):
        self._put_in_cache("a", 2)

if __name__ == "__main__":
    b1 = B1()
    b2 = B2()

    b2.p()
    b1.p()

out:

2


Notice _get_from_cache and _put_in_cache are methods, but they can be @staticmethods, as they only ever access class variables, and their self isn't "really" ever being used. __cache could theoretically be accessed directly by children, but the _get_from_cache and _put_in_cache makes __cache private, and gives a protected API to it.

Gulzar
  • 23,452
  • 27
  • 113
  • 201
1

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.

Gulzar
  • 23,452
  • 27
  • 113
  • 201