0

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!

3
  • Hmm, your code looks OK. Can you make a minimal working example? Commented May 20, 2012 at 9:38
  • Why did you try something different, if the first thing worked? And if you're handing over a (list, tuple, ...) to the function, then don't use *args in parameter, because you'll get a tuple with the list in it, use args instead. Commented May 20, 2012 at 9:44
  • You can also write your invoke body like this: getattr(obj, method_name)(*args) just a FYI :) Commented May 20, 2012 at 10:40

2 Answers 2

5

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

invoke(module, 'foo', *(1, 2))
Sign up to request clarification or add additional context in comments.

Comments

1

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))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.