2

What's the best way to pass a method and a method parameter to another method?

Is there a better way to do the following?

def method1(name)
    return 'Hello ' + name

def method2(methodToCall, methodToCallParams, question):
    greetings = methodToCall(methodToCallParams)
    return greetings + ', ' + question

method2(method1, 'Sam', 'How are you?')
Dan
  • 3,636
  • 2
  • 24
  • 24
  • What are you trying to do with this? Why pass a method and parameters? Why not just call the method and be done with it? – S.Lott Apr 01 '09 at 19:03
  • this is a bad example but my method2 is actually a try method, it will call method1 x amount of time and fails.. I'm tryint to make it as a helper method so I can pass a bunch of different methods to try – Dan Apr 01 '09 at 20:44

5 Answers5

11

If you want to package the invocation up in one hit, you can use the functools module:

from functools import partial

def some_function(param_one, param_two):
    print "Param One: %s" % param_one
    print "Param Two: %s" % param_two

def calling_function(target):
    target()

calling_function(partial(some_function, "foo", "bar"))

You can do tweakier things with functools.partial too, such as binding only some parameters, leaving you with a function with a new signature. It's overkill in a lot of cases to use it but it certainly has it's place.

jkp
  • 78,960
  • 28
  • 103
  • 104
  • wow this is exactly what I'm looking for except that I'm on python 2.4 and this requires 2.6 :( If I don't get a better answer, I'll accept your answer – Dan Apr 01 '09 at 18:48
  • I just posted an answer showing how to create a roughly equivalent function to functools.partial for use with Python versions prior to 2.5, in conjunction with @jkp's answer it should get the job done. – Jay Apr 02 '09 at 00:51
3

You could do it this way:

def method1(name):
    def wrapper():
        return 'Hello ' + name
    return wrapper

def method2(method, question):
    output = method()
    return output + ', ' + question

method2(method1(name = 'Sam'), 'How are you?')

You can of course pass some variables in the method() call too:

def method1(name):
    def wrapper(greeting):
        return greeting + name
    return wrapper

def method2(method, question):
    output = method(greeting = 'Hello ')
    return output + ', ' + question

method2(method1(name = 'Sam'), 'How are you?')
Caotic
  • 954
  • 6
  • 4
2

You can used functools.partial to do this, as jkp pointed out

However, functools is new in Python 2.5, so to handle this in the past I used the following code (this code is in the Python docs for functools.partial, in fact).

# functools is Python 2.5 only, so we create a different partialfn if we are
# running a version without functools available
try:
    import functools
    partialfn = functools.partial
except ImportError:
    def partialfn(func, *args, **keywords):
        def newfunc(*fargs, **fkeywords):
            newkeywords = keywords.copy()
            newkeywords.update(fkeywords)
            return func(*(args + fargs), **newkeywords)
        newfunc.func = func
        newfunc.args = args
        newfunc.keywords = keywords
        return newfunc
Community
  • 1
  • 1
Jay
  • 41,768
  • 14
  • 66
  • 83
1

Another option, if you are working on a Python version pre 2.5 is to use a lambda as a closure:

def some_func(bar):
    print bar

def call_other(other):
    other()

call_other(lambda param="foo": some_func(param))

HTH

jkp
  • 78,960
  • 28
  • 103
  • 104
0

You're thinking of currying, where you bind a function and arguments together to be called later. Usually currying is used so that you can add additional arguments at the time the function is actually called.

Rather than re-write the wheel, here's a link to an example: http://code.activestate.com/recipes/52549/.

If, however, the case you've mocked up in the question really is that simple, you can pass a list of args as positional parameters, or a list of kwargs as named parameters, to another function.

def method1(name):
    return 'Hello %s' % name

args = ['Joe']
method1(*args)

def method1a(name=None, salutation=None):
    return 'Hello %s %s' % (name, salutation)

kwargs = {'name':'Joe', 'salutation':'Mr'}
method1a(**kwargs)
Jarret Hardie
  • 95,172
  • 10
  • 132
  • 126
  • This doesn't really answer the question: you're only showing how to pack and unpack arguments, not how to bind them to a function and pass it around as one. – jkp Apr 01 '09 at 19:53