Python: Initialising a new derived class in a method of a base class
Question: My situation is that I have access to two classes that work nicely together.
Modifying their code extensively is probably not possible but maybe small
changes could be implemented. However, there are some small extensions to both
classes that I would like to make. This seems like a job for subclassing,
deriving from each class and adding functionality. But I've run into a problem
because one base class calls the other, not my derived one.

Let's say I have two classes A and B in a module 'base_classes.py'. Class B
has a method that creates an instance of class A and uses it e.g.

'base_classes.py'

    
    
    class A():
        def __init__(self):
            print('Class A being called')
    
    class B():
        def __init__(self):
            self.do_thing()
        def do_thing(self):
            self.myA = A() # Here class A is explicitly named
    

So I would like to subclass these two and extend them. I do that in a separate
module:

'extensions.py'

    
    
    import base_classes
    
    class DerivedA(base_classes.A):
        def __init__(self):
            super().__init__()
            print('Class DerivedA being called')
    
    class DerivedB(base_classes.B):
        pass
    
    db = DerivedB()
    

As expected the output is simply

    
    
    Class A being called  
    

But how can I prevent _my subclass of B_ from making the instance of the base
class of A in the method `do_thing(self)` and instead make an instance of
DerivedA?

The simple way would be to override `do_thing(self)` in DerivedB so that it
explicitly calls DerivedA e.g.

    
    
    class DerivedB(base_classes.B):
        def do_thing(self):
            self.myA = DerivedA() # Here class DerivedA is explicitly named
    

This is fine for this small example, but what if `do_thing(self)` was a
hundred lines long and contained many objects of type A? What if most methods
in B contained some A objects. You'd have to override basically every method
with an almost exact replica, making it pointless to derive from B in the
first place. That's pretty much the problem in my case and I think there must
be a clever pythonic way to solve this. Ideally without completely rewriting
the original classes.

Any ideas?


Answer: You can change the `do_thing` method on class B and pass a class in parameter
:

    
    
    class B():
        def __init__(self):
            self.do_thing()
        def do_thing(self, klass=A):
            self.myA = klass()
    

Then derivedB `do_thing` method can call it with DerivedA

    
    
    class DerivedB(base_classes.B):
        def do_thing(self, klass=DerivedA):
            return super(DerivedB, self).do_thing(klass)
    

