0

Suppose I have the following loader method:

    #################################
    # Load a class
    #################################
    def __load_class(self, module_name, class_name, params):
        try:
            loaded_class = getattr(importlib.import_module(module_name), class_name)
            obj = loaded_class(params)
            return obj
        except Exception as ex:
            self.logger.error("FAILED to load class: {0}.{1}\n{2}".format(module_name, class_name, traceback.format_exc()))

How do I pass the params needed to instantiate my class to this method? I have classes that take 1 parameter and others that take 2 parameters.

NOTE: I have no control of the classes I am trying to instantiate. I can't change their arguments.

Denis
  • 11,796
  • 16
  • 88
  • 150
  • If you set your class constructor to take in named parameters, you can change params to `**kwargs` then do `loaded_class(**kwargs)`. – absolutelydevastated Sep 09 '19 at 16:33
  • 2
    you can use *args and/or **kwargs depending on the client code – Dov Rine Sep 09 '19 at 16:33
  • Possible duplicate of [What is the purpose and use of \*\*kwargs?](https://stackoverflow.com/questions/1769403/what-is-the-purpose-and-use-of-kwargs) – pault Sep 09 '19 at 16:34
  • I have no control of the classes I am trying to instantiate. I can't change their arguments. I don't think any of the links to duplicates are helpful. They say to change the arguments of my classes which I can't do. – Denis Sep 09 '19 at 16:41

2 Answers2

1

You can determine the arguments required dynamically like so:

class MyClass:
    def __init__(self, param1, param2):
        # do stuff

args = MyClass.__init__.__code__.co_varnames
print(args)
> ('self', 'param1', 'param2')

From there you can extract only the params needed from your param list. Use the unpack operator (* for args, ** for kwargs)

params = {'param1': 'foo', 'param2': 'bar', 'param3': 'baz'}
params_to_pass = {argname:params[argname] for argname in args[1:]} # ignore 'self'

obj = MyClass(**params_to_pass)
C_Z_
  • 7,427
  • 5
  • 44
  • 81
  • suppose I have no control over the classes that I am trying to instantiate. I can't change them. I am just writing a dynamic instantiator – Denis Sep 09 '19 at 16:37
0

I think this will work:

    #################################
    # Load a class
    #################################
    def __load_class(self, module_name, class_name, params):
        try:
            loaded_class = getattr(importlib.import_module(module_name), class_name)
            obj = loaded_class(*params)
            return obj
        except Exception as ex:
            self.logger.error("FAILED to load class: {0}.{1}\n{2}".format(module_name, class_name, traceback.format_exc()))

and then I would call it like:

self.__load_class(module_name, class_name, [arg1])

or

self.__load_class(module_name, class_name, [arg1, arg2])
Denis
  • 11,796
  • 16
  • 88
  • 150
  • This isn't as clean as @C_Z_ answer so accepting that one but for my code this answer works great! – Denis Sep 09 '19 at 19:33