Home > Software engineering >  How do you invoke a method on a class instance by string name?
How do you invoke a method on a class instance by string name?

Time:02-15

I am trying to invoke a method on a class dynamically using a String for the class name and a String for the method name. I am using getattr then invoking a method on the class. You'll have to forgive me if I am way off, I am kind of new to Python.

class mock:

    def __init__(self):
        pass

    def create(self):
        print('hello world?')
        return 'hello world'

then creating the instance and invoking via :

module = importlib.import_module('xyz.module')
instance = getattr(module, 'mock')
invoke = getattr(instance, 'create')
result = invoke()
print(result)

The result is something like <object object at 0x10943ccd0>. "hello world?" is never printed. What am I doing wrong?

CodePudding user response:

You have missed a step. The instance variable you have isn't actually an instance, it's the class mock itself. You need to call it to get an instance. Try something like this:

module = importlib.import_module('xyz.module')
klass = getattr(module, 'mock')       # rename this variable (avoiding keywords)
instance = klass()                    # and call the class to create an instance
method = getattr(instance, 'create')  # also renamed here, for clarity
result = method() # previously, this would have been an error (missing self argument)
print(result)     # now you should get "hello world" printed twice (once with a ?)

As a note, PEP 8 naming conventions would have helped you avoid the issue here. If you'd used the name Mock instead of mock for the class, it might have been a bit more obvious what kind of thing you had, after importing and getattring it.

CodePudding user response:

You don't need getattr at all; the instance returned by import_module is the same thing that would be implicitly bound to xyz.module had you used an import statement.

module = importlib.import_module('xyz.module')
result = module.mock().create()
assert result == "hello world"

Note that the above creates an instance of mock on which to call create, rather than accessing mock.create directly. If you have variables containing the name of the class and the method, you still need to do that, only using getattr this time.

module = importlib.import_module('xyz.module')
cls_name = 'mock'
method_name = 'create'

cls = getattr(module, 'mock')
instance = cls()
invoke = getattr(instance, 'create')
result = invoke()
assert result == "hello world"
  • Related