[python] Passing functions with arguments to another function in Python?

Is it possible to pass functions with arguments to another function in Python?

Say for something like:

def perform(function):
    return function()

But the functions to be passed will have arguments like:

action1()
action2(p)
action3(p,r)

This question is related to python function

The answer is


This is what lambda is for:

def perform(f):
    f()

perform(lambda: action1())
perform(lambda: action2(p))
perform(lambda: action3(p, r))

Use functools.partial, not lambdas! And ofc Perform is a useless function, you can pass around functions directly.

for func in [Action1, partial(Action2, p), partial(Action3, p, r)]:
  func()


This is called partial functions and there are at least 3 ways to do this. My favorite way is using lambda because it avoids dependency on extra package and is the least verbose. Assume you have a function add(x, y) and you want to pass add(3, y) to some other function as parameter such that the other function decides the value for y.

Use lambda

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# run example
def main():
    f = lambda y: add(3, y)
    result = runOp(f, 1) # is 4

Create Your Own Wrapper

Here you need to create a function that returns the partial function. This is obviously lot more verbose.

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# declare partial function
def addPartial(x):
    def _wrapper(y):
        return add(x, y)
    return _wrapper

# run example
def main():
    f = addPartial(3)
    result = runOp(f, 1) # is 4

Use partial from functools

This is almost identical to lambda shown above. Then why do we need this? There are few reasons. In short, partial might be bit faster in some cases (see its implementation) and that you can use it for early binding vs lambda's late binding.

from functools import partial

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# run example
def main():
    f = partial(add, 3)
    result = runOp(f, 1) # is 4

You can use the partial function from functools like so.

from functools import partial

def perform(f):
    f()

perform(Action1)
perform(partial(Action2, p))
perform(partial(Action3, p, r))

Also works with keywords

perform(partial(Action4, param1=p))

(months later) a tiny real example where lambda is useful, partial not:
say you want various 1-dimensional cross-sections through a 2-dimensional function, like slices through a row of hills.
quadf( x, f ) takes a 1-d f and calls it for various x.
To call it for vertical cuts at y = -1 0 1 and horizontal cuts at x = -1 0 1,

fx1 = quadf( x, lambda x: f( x, 1 ))
fx0 = quadf( x, lambda x: f( x, 0 ))
fx_1 = quadf( x, lambda x: f( x, -1 ))
fxy = parabola( y, fx_1, fx0, fx1 )

f_1y = quadf( y, lambda y: f( -1, y ))
f0y = quadf( y, lambda y: f( 0, y ))
f1y = quadf( y, lambda y: f( 1, y ))
fyx = parabola( x, f_1y, f0y, f1y )

As far as I know, partial can't do this --

quadf( y, partial( f, x=1 ))
TypeError: f() got multiple values for keyword argument 'x'

(How to add tags numpy, partial, lambda to this ?)


Here is a way to do it with a closure:

    def generate_add_mult_func(func):
        def function_generator(x):
            return reduce(func,range(1,x))
        return function_generator

    def add(x,y):
        return x+y

    def mult(x,y):
        return x*y

    adding=generate_add_mult_func(add)
    multiplying=generate_add_mult_func(mult)

    print adding(10)
    print multiplying(10)