0

My requirement is to dynamically instantiate a class based on particular strings. The catch over here is that new class has inheritance on some other classes. The issue is that I am not able to see the code getting executed from the Inherited class.

I have tried to do this by having a class as SystemConfigure which will call the particular class based on the parameters given in a dict. In my code I am dynamically calling the Super Class which inherits functions from the Base class. I don't see the code in the Base class getting executed.

Please let me know how can this be done.

Code

class SystemConfigure():

    def __init__(self,snp_dict):
        dict = snp_dict
        osname = dict['osname']
        protocol = dict['protocol']
        module = protocol
        func_string = osname + "_" + protocol + "_" + "Configure"
        print ("You have called the Class:", module, "and the function:", func_string)
        m = globals()[module]
        func = getattr(m, func_string)
        func(dict)

class Base():

    def __init__(self):
        pass
        print("BASE INIT")

    def Unix_Base_Configure(dict):
        print ("GOT IN THE UNIX BASE CLASS FUNCTION")

    def Linux_Base_Configure(dict):
        print("GOT IN THE LINUX BASE CLASS FUNCTION")

class Super(Base):

    def __init__(self):
        dict = dict
        Base.__init__(self)
        Base.Unix_Base_Configure(dict)

    def Unix_Super_Configure(dict):
        print ("GOT IN THE UNIX SUPER CLASS FUNCTION", dict)

n = SystemConfigure({'protocol':'Super','osname':'Unix','device':'dut'})

Output

You have called the Class: Super and the function: Unix_Super_Configure
GOT IN THE UNIX SUPER CLASS FUNCTION {'protocol': 'Super', 'osname': 'Unix', 'device': 'dut'}

Expectation

I was expecting the "GOT IN THE UNIX BASE CLASS FUNCTION" error to be printed. The output needs to be printed before the "GOT IN THE UNIX SUPER CLASS FUNCTION" message.

Cœur
  • 37,241
  • 25
  • 195
  • 267
user2905950
  • 41
  • 1
  • 1
  • 4
  • 1
    Your code has multiple errors. You're never instantiating your classes, so neither `__init__` is ever called. Your "configure" methods also don't accept a `self` argument. – BrenBarn Apr 21 '17 at 19:05

2 Answers2

0

That is typically a job for metaclasses in Python.
Quickly explained, metaclasses can be used to define 'how' a class is 'created'.
Review the docs or look for 'python metaprogramming tutorials' for more info about that topic (So: What are Python metaclasses useful for?

class BaseMetaClass(type):
    def __new__(meta, name, bases, dct):
        return super(BaseMetaClass, meta).__new__(meta, name, bases, dct)

    def __init__(cls, name, bases, dct):
        super(BaseMetaClass, cls).__init__(name, bases, dct)

    def __call__(cls, *args, **kwds):
        if args and isinstance(args[0], dict):
            if 'osname' in args[0]:
                cls.osname = args[0]['osname']
            else:
                cls.osname = "undefined os"

            cls.base_configure = "GOT IN THE %s BASE CLASS FUNCTION" % cls.osname.upper()
        return type.__call__(cls, *args, **kwds)


class SystemConfigure(metaclass=BaseMetaClass):
    def __init__(self, snp_dict):
        print (self.base_configure)

n = SystemConfigure({'protocol':'Super','osname':'Unix','device':'dut'})
n = SystemConfigure({'protocol':'Super','osname':'Linux','device':'dut'})
n = SystemConfigure({'protocol':'Super','device':'dut'})

returns:

GOT IN THE UNIX BASE CLASS FUNCTION
GOT IN THE LINUX BASE CLASS FUNCTION
GOT IN THE WINDOWS BASE CLASS FUNCTION
Community
  • 1
  • 1
Maurice Meyer
  • 17,279
  • 4
  • 30
  • 47
0

You need to define some of the methods as @staticmethods since they don't have a self argument (or need one). Below is your code with them # ADDED.

I also changed how the dictionary argument passed to SystemConfigure() is handled so it now takes advantage of Python keyword argument passing to create a dictionary to pass it, but that change isn't strictly required.

class SystemConfigure():
    def __init__(self, **kwargs):  # CHANGED - argument snp_dict into **kwargs
        # dict = snp_dict  # REMOVED - no longer needed
        osname = kwargs['osname']
        protocol = kwargs['protocol']
        module = protocol
        func_string = osname + "_" + protocol + "_" + "Configure"
        print ("You have called the Class:", module, "and the function:", func_string)
        m = globals()[module]
        func = getattr(m, func_string)
        func(kwargs)

class Base():
    def __init__(self):
        pass
        print("BASE INIT")

    @staticmethod  # ADDED
    def Unix_Base_Configure(dict):
        print ("GOT IN THE UNIX BASE CLASS FUNCTION")

    @staticmethod  # ADDED
    def Linux_Base_Configure(dict):
        print("GOT IN THE LINUX BASE CLASS FUNCTION")

class Super(Base):
    def __init__(self):  # THIS IS NEVER CALLED
#        dict = dict  # REMOVED - don't know what this is all about...
        Base.__init__(self)
        Base.Unix_Base_Configure(dict)  # why is a type being passed?

    @staticmethod  # ADDED
    def Unix_Super_Configure(dict_):
        print ("GOT IN THE UNIX SUPER CLASS FUNCTION", dict_)

# Changed how dictionary argument is created into a more (IMO) readable form (optional)
n = SystemConfigure(protocol='Super', osname='Unix', device='dut')

Output:

You have called the Class: Super and the function: Unix_Super_Configure
GOT IN THE UNIX SUPER CLASS FUNCTION {'protocol': 'Super', 'osname': 'Unix', 'device': 'dut'}
martineau
  • 119,623
  • 25
  • 170
  • 301