sogno
sogno

Reputation: 219

Python: How to call methods with various signature dynamically

I'm writing a test automation tool with Python. A key feature of the tool is to call methods by names with various signature just like what C# reflection does. How ever, after reading a bunch of articles and doing several tests, I failed to find a way to deal with the various signature.

This is my first thought -

def invoke(obj, method_name, *args):
    print type(args)
    method = getattr(obj, method_name)
    method(*args)

import sys
module = sys.modules[__name__]
invoke(module, 'foo', 1, 2) 

It does work. But the problem is, the methods called by their names can have different number of parameters. Then I was thinking that the pararmeter list could be reprensented by a tuple since the type of args is a tuple. So I change the last line of code -

invoke(module, 'foo', (1, 2)) # pass parameter list using a tuple (1, 2)

but the interpreter told me this -

Traceback (most recent call last):
  File "\Src\studies\dynamic_method_call.py", line 14, in <module>
    invoke(module, 'foo', (1, 2))
  File "\Src\studies\dynamic_method_call.py", line 9, in invoke
    print method(*args)
TypeError: foo() takes exactly 2 arguments (1 given)

I also tried list, and keywored args. Neither of them worked. Please advise!

Upvotes: 0

Views: 280

Answers (2)

Eric
Eric

Reputation: 97641

invoke(module, 'foo', (1, 2)) expands to foo((1, 2)) so args is ((1, 2),). That calls foo with one argument, not two, hence your error.

Either use:

def invoke(obj, method_name, *args):
    method = getattr(obj, method_name)
    method(*args)

invoke(module, 'foo', 1, 2)

Or

def invoke(obj, method_name, args):
    method = getattr(obj, method_name)
    method(*args)

invoke(module, 'foo', (1, 2))

Upvotes: 1

Adam Zalcman
Adam Zalcman

Reputation: 27233

In order to "unpack" a tuple of values as arguments to a function call, just use *, e.g.:

invoke(module, 'foo', *(1, 2))

Upvotes: 5

Related Questions