Question

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.

Was it helpful?

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

OTHER TIPS

You can use class variables:

base.context = 'context'
A = a(1)
B = b(2)
#...

The way to eliminate redundancy is to identify repeated patterns, and factor out the pattern into some separate bit of code.

Not sure if it's your real code, but from your example the pattern is that you're instantiating a whole bunch of classes in a similar way. Even if you removed the 9 characters from each line required to type context,, you're still doing:

A = a(1)
B = b(2)
C = c(3)
...

Which would drive me nuts. The problem with the redundancy is not so much the typing, but that if you want to change this (say you want to start at 0, or you want to add an additional argument to each class, or whatever) you have to change every line.

So I would rather do something like this:

classes = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
instances = [cls(context, i) for i, cls in enumerate(classes, 1)]

Here I've got code that clearly says I'm instantiating a whole bunch of classes, and that I am passing context to each one, along with an integer from 1 to the number of classes I have (increasing for each class). And it's easy to independently decide to change what the list of classes is, or what I'm passing to each class.

It does mean my instances have names like instances[0] and instances[13] instead of A and N. There are ways around that too, but I find it rare to be instantiating a collection of things and then use them as independent individual things rather than as a collection.

You should define context as a class attribute of base. Modifying your example would be:

class base:

    context = None

    def common_method(self):
        pass

class A(base):
    def __init__(self, aa):
        pass

class B(base):
    def __init__(self, bb):
       pass

.
.
.

class Z(base):
    def __init__(self, zz):
        pass

base.context = get_context_from_some_method()
A = a(1)
B = b(2)
Z = z(3)    

All A, B and Z instances shares the same context property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top