Search code examples
pythonpolymorphismderived-classbase-classderived

Implement Python class based on the parameter passed to constructor


I am implementing a python class, which constructs another object in the constructor whose type is determined based on the parameter passed to it. For example in the code below "workerA" has the behavior of class "MyAClass" and "workerB" object has the behavior of "MyBClass".

I am using this method instead of deriving different class from the base class because the BaseClass is already being used in a different code which cannot be changed. So if I want another behavior of BaseClass as for "MyBClass" behavior then I only need to passed the parameter dbtype = "MyBClass" to it.

Is there any better method which can be used and which gives the same result?

  import sys

  # MyAClass definition
  class MyAClass :

     def __init__(self, serverSettings):
        self._serverSettings = serverSettings

     def initialize(self):
        self._init = 1;
        print("Calling", sys._getframe(1).f_code.co_name)

     def add(self):
        self._init = 2;
        print("Calling", sys._getframe(1).f_code.co_name)

     def finalize(self):
        self._init = 3;
        print("Calling", sys._getframe(1).f_code.co_name)

     def __del__(self):
        print('Calling destructor of class ', self.__class__.__name__)


  # MyBClass definition
  class MyBClass :

     def __init__(self, serverSettings):
        self._serverSettings = serverSettings

     def initialize(self):
        self._init = 1;
        print("Calling", sys._getframe(1).f_code.co_name)

     def add(self):
        self._init = 2;
        print("Calling", sys._getframe(1).f_code.co_name)

     def finalize(self):
        self._init = 3;
        print("Calling", sys._getframe(1).f_code.co_name)

     def __del__(self):
        print('Calling destructor of class ', self.__class__.__name__)


  # The base class which will be called in main program
  class BaseClass :

     def __init__(self, serverSettings, dbtype = None):

        if(dbtype == None):
           self.__worker = MyAClass(serverSettings)
        elif(dbtype == "MyBClass") :
           self.__worker = MyBClass(serverSettings)
        else :
           print("Undefined type")

     def initialize(self):
        self.__worker.initialize()

     def add(self):
        self.__worker.add()

     def finalize(self):
        self.__worker.finalize()


  if __name__ == "__main__":

     serverSettings = dict()

     serverSettings["address"] = "localhost"
     serverSettings["name"] = "Testname"

     workerA = BaseClass(serverSettings)
     workerA.add()

     workerB = BaseClass(serverSettings, dbtype = "MyBClass")
     workerB.finalize()

Solution

  • I know this doesn't produce the same output as your original program, but would something like this work for your purposes? Unless you're querying the method name (as you are above), you should get functionally identical results.

    class BaseClass :
        def __init__(self, serverSettings, dbtype=None):
    
            if(dbtype == None):
               self.__worker = MyAClass(serverSettings)
            elif(dbtype == "MyBClass") :
               self.__worker = MyBClass(serverSettings)
            else :
               print("Undefined type")
    
        def __getattribute__(self, x):
            settings = object.__getattribute__(self, '__dict__').get('_BaseClass__worker')
            return settings.__getattribute__(x)
    

    Alternately, using some class twizzing like this:

    class BaseClass :
        def __init__(self, serverSettings, dbtype='MyAClass'):
            dbtypes = {'MyAClass': MyAClass,
                        'MyBClass': MyBClass}
            if dbtype not in dbtypes:
               raise("Undefined type")
            self.__class__ = dbtypes[dbtype]
            self.__init__(serverSettings)