Passing functions with arguments to another functi

2019-01-01 17:13发布

问题:

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)

回答1:

Do you mean this?

def perform( fun, *args ):
    fun( *args )

def action1( args ):
    something

def action2( args ):
    something

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


回答2:

This is what lambda is for:

def Perform(f):
    f()

Perform(lambda: Action1())
Perform(lambda: Action2(p))
Perform(lambda: Action3(p, r))


回答3:

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


回答4:

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



回答5:

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



回答6:

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


回答7:

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)