Search code examples
pythonclassoverlapping-instances

How to share common context between classes?


Present Scenario :

I have a set of classes that all take a common argument context in constructor, and all the classes inherit from a common base.

class base:
    def common_method(self):
        pass

class a(base):
    def __init__(self,context, aa):
        pass

class b(base):
    def __init__(self, context, bb):
        pass

# ...

class z(base):
    def __init__(self, context, zz):
        pass

Usage in main:

context = get_context_from_some_method()

A = a(context, 1)
B = b(context, 2)
C = c(context, 3)
D = d(context, 4)
.
.
.
Z = z(context, 26)

Problem:

  • Is there a tricky way possible to supply context to all the classes implicitly ?
  • We have a common base class, but I don't see a obvious way to let it set the context for all the classes.
  • It can be assumed that I want to keep context common to all my class instances.
  • Just a random thought - Can meta class help somehow ?

I know it seems silly, but I just want to get rid of the redundancy in some way, so that I can set a global context somehow and concentrate on my objects.

Please suggest some way around ?

** Update to Question **

I can-not set a context in the base class, since this is to be used in a web application. So, many pages with different context will be using the class structure. So, If I set a context in base then it will conflict to the context that will be set by another instance of webpage that will use the same base. Since, in a web-application all the above classes will be in memory common to all pages.


Solution

  • Edit: If you don't want to / can't use a class variable, your best bet is to use a factory function. Either make it a static method on the base class, or a module level function.

    def make_instances(context, *instances):
        return [cls(context, *args) for cls, args in instances]
    
    A, B, ..., Z = make_instances(get_context_from_some_method(), 
                     (a, (1,)), (b, (2,)), ..., (z, (26,)))
    
    # or
    instances = make_instances(get_context_from_some_method(), 
                 zip(list_of_subclasses, ((x,) for x in range(1, 27))))
    

    Alternatively, and I don't know if this works in your situation, just use a module level global variable:

    class z(base):
        def __init__(self, zz):
            self.zz = zz
            self.context = context
    
    context = 'abc'
    Z = z(26)
    

    In addition to the advice to use class variables from the other answer, I advise you to copy the context onto the instances, so that you can later change the context without affecting already created instances.

    class base:
        context = None # if you want to be able to create without context.
        # just omit the previous line if you want an error
        # when you haven't set a context and you try to instantiate a subclass
    
    class a(base):
        def __init__(self, aa):
            self.aa = aa
            self.context = self.context # sets an instance variable
            # so the class variable can be changed
    
    class b(base):
        def __init__(self, bb):
            self.bb = bb
            self.context = self.context
    
    base.context = 'context'
    
    A = a(1)
    B = b(2)
    
    base.context = 'newcontext'
    
    print A.context # context