Search code examples
pythonoopmultiple-inheritance

Conditional Inheritance neglects changed condition in workspace in python


I have two classes that have a similar structure but different functionality. I want a third class to be able to inherit from either of them based on my needs. Let's say I have an objects module and I have defined classes A, B, and C in the module. This is how I do the conditional inheritance after a syntax I found on the internet:

cond = True

class C(A if cond else B):

    def __init__(self):
        super.__init__()

in which A and B are other classes in the module objects. Now when I import objects and class C from the objects module into a jupyter notebook and change the cond:

objects.cond = False
my_class = C()

No effect seems to be taking place as I check the name of the parent class. Meaning that after changing the condition, I expect the class C to inherit from B, but instead it inherits from class A as if cond still evaluates to True. I have tried with not importing the class from the module and just import the objects module and instantiate my class with my_class = objects.C() but still the new condition will not be issued.

Now it is not difficult in my case just to change the condition manually inside the module whenever I need to, but I was wondering what all of this says about python's syntax. Am I doing something wrong or is this because of some sort of command priority between the module and class level in python? Or could the syntax be possibly wrong?

N.B. I have not written a complete class C, other stuff is being done in class C and some of them would change based on which parent is inherited. The code is to serve as a dummy but IMO sufficient example.


Solution

  • Explanation

    Python import works as follows:

    • It executes the code in the module
    • Symbols created by executing the module code are placed in the module symbol table (including class C)
    • import only loads a module once (i.e. the module is cache) for a process. Thus, subsequent imports of the same module has no effect.
    • Consequently, the definition for class C is placed in the module symbol table on the first import. Changing cond after the import thus has no affect on the definition.
    • Use reload to force the reload of a module (i.e. not using the cache version).

    Sharging global variables across modules

    • A suggested approach is the place the global shared variables in a config module

    Considering the above the following code works.

    Code

    config.py (contains globals to share across modules)

    cond = True
    

    test_abc.py (contains the definition of classes a, b, c)

    import config
    
    class A(): 
        def __init__(self, x): 
            self.x = x
          
        def getX(self): 
            return f"A {self.x}"
        
    class B(): 
        def __init__(self, x): 
            self.x = x
          
        def getX(self): 
            return f"B {self.x}"   
      
    # inherits from A or B
    class C(A if config.cond else B):
        def __init__(self, x):
            super().__init__(x)
            
    

    main.py (main program)

    from importlib import reload             # Allows reloading of modules
    import config                            # place variables we want to share across modules
    
    # Test with cond = True
    config.cond = True                       # Use True in condition for inheritance                         
    import test_abc                            # Use import first time, can reload on subsequent calls
    ca = test_abc.C(1)
    print("First call: ", ca.getX())         # Test that we obtain A object
    
    # Test with cond = False
    config.cond = False
    reload(test_abc)                          # reload module
    
    ca = test_abc.C(1)
    print("Second call:", ca.getX())        # Test that we obtained B object
    

    Output

    First call:  A 1
    Second call: B 1