0

I'm attempting to pass a class method as an argument to another class method. Below is an example...

import time

class MyClass(object):

    def doSomething(self,argument2,argument3):
        print argument2,argument3

    def attemptTenTimes(self,fun,*args):
        attempt = 0
        while True:
            try:
                print 'Number of arguments: %s' % len(*args)
                print args
                output = fun(*args)
                return output
            except Exception as e:
                print 'Exception: %s' % e
                attempt += 1
                time.sleep(10)
                if attempt >= 10: return
                else: continue

MC = MyClass()
MC.attemptTenTimes(MC.doSomething,(MC,'argument2','argument3',))

The output is....

Number of arguments: 3
((<__main__.MyClass object at 0x7f7e6be4e390>, 'argument2', 'argument3'),)
Exception: doSomething() takes exactly 3 arguments (2 given)
Number of arguments: 3
((<__main__.MyClass object at 0x7f7e6be4e390>, 'argument2', 'argument3'),)
Exception: doSomething() takes exactly 3 arguments (2 given)
Number of arguments: 3
((<__main__.MyClass object at 0x7f7e6be4e390>, 'argument2', 'argument3'),)
Exception: doSomething() takes exactly 3 arguments (2 given).............

I am passing three arguments to the function doSomething, however, this exception keeps coming up. I've used functions as arguments to other functions before, but this is my first time doing it within the context of a class. Any help would be appreciated. Thanks.

b10hazard
  • 7,399
  • 11
  • 40
  • 53
  • Worth mentioning: neither of the methods in question are class methods. `classmethod` means something specific in Python, see [this](http://stackoverflow.com/questions/38238/what-are-class-methods-in-python-for) [stuff](http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner). – Henry Keiter Mar 27 '13 at 15:46

1 Answers1

1

You've not passed three arguments; you passed two. You need this:

MC.attemptTenTimes(MC.doSomething,*('argument2','argument3'))

or this (equivalent):

MC.attemptTenTimes(MC.doSomething,'argument2','argument3')

The attemptTenTimes function has the parameter *args, which collects positional arguments into a tuple referred to locally as args. You're passing it the whole tuple as the only positional argument, so locally you have a variable named args that looks like ((MC,'argument2','argument3'),). As a result, when you unpack it and pass it to your function, you're just passing the inner tuple.

As an aside, you also shouldn't be unpacking args when you pass it to len, because that'll throw an error. You just want len(args) on line 12 up there.

Alternately, you could change your attemptTenTimes function signature to this:

def attemptTenTimes(self,fun,args):

You could then pass the whole args tuple to it, as you were originally doing. I believe using *args is more standard, though, and personally I think it's clearer.

Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
  • Grrr, I should have caught that! Your answer helped. I used what you said, except that the "MC" was not necessary in that tuple. I used *('argument2','argument3',) and it worked! – b10hazard Mar 27 '13 at 15:30
  • 1
    The reason that `MC` isn't required is that `MC.doSomething` is already bound to the instance you created, so it only needs the two arguments beyond `self`. Alternatively you can invoke it `MC.attemptTenTimes(MyClass.doSomething, MC, 'arg2', 'arg3')`. Of course, it's easier to use it when bound, but I thought it bore mentioning :-) – Dan Lecocq Mar 27 '13 at 15:40