简体   繁体   中英

Python: Initialising a new derived class in a method of a base class

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 eg

'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 eg

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?

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM