简体   繁体   中英

A function that returns a function (in python)

Is it possible to create a function which takes lambda functions as arguments (with each lambda function using argument x ) and then returns a new function which has a single argument x and returns the product of all the lambda functions?

Here's my non-working example:

def func_you( lambdafunc1, lambdafunc2, lambdafunc3, lambdafunc4):
    return def func_you_2(x):
        return lambdafunc1(x) * lambdafunc2(x) * lambdafunc3(x) * lambdafunc4(x)

So essentially what happens is you have a function func_you which takes 4 lambda functions each using argument x . As an example, the argument for lambdafunc1 could be something like lambda x: x + 10 .

func_you then returns a new function called func_you_2 whose output is the product of all those lambda functions and has one argument x which is passed onto the x argument of each of func_you 's lambda functions.

Assuming what I'm trying to do is possible, how do I convey the proper syntax to do it?

Also, is there a specific name for this kind of thing rather than "function that returns a function"? It's technically not a nested function, right?

My answer is no better than any other answer so far, but I wanted to tweak it a bit to squeeze a little more functional-programming-juice out of the question, just for fun.

from functools import reduce
from operator import mul

def functioners(*funcs):
    def inner(x):
        return reduce(mul, [f(x) for f in funcs], 1)
    return inner

In [2]: res = functioners(lambda x: x+1, lambda x: x *2, lambda x: x+3)

In [3]: res(5)
Out[3]: 480

In [4]: res = functioners(lambda x: x+1, lambda x: x +1, lambda x: x+1)

In [5]: res(1)
Out[5]: 8

Edit

I even got a little crazier with it in order to implement a kind-of 10-minute currying attempt. This is not something I would ever subject my coworkers to, but it's late where I am so maybe just for fun...

It should be possible to define a function that can keep returning a partially applied version of itself, but I guess you need some way to tell it to stop?

Here's my attempt:

from functools import partial, reduce
from operator import mul

def functionals(*funcs, finished=None):
    def inner(x):
        return reduce(mul, [f(x) for f in funcs], 1)

    if finished is not None:
        # stop condition
        return inner
    else:
        return partial(functionals, *funcs)

You could use it like this (if you were so inclined...)

In [37]: f1 = functionals(lambda x: x+1)

In [38]: f2 = f1(lambda x: x + 1)

In [39]: f3 = f2(lambda x: x + 1, lambda x: x + 1, lambda x: x + 1)

In [40]: f3(finished="definitely!")(1)
Out[40]: 32

(I will get my hat and coat now...)

You can return a lambda function that does what you want. Example -

def func_you( lambdafunc1, lambdafunc2, lambdafunc3, lambdafunc4):
    return lambda x: lambdafunc1(x) * lambdafunc2(x) * lambdafunc3(x) * lambdafunc4(x)

Demo -

>>> def func_you( lambdafunc1, lambdafunc2, lambdafunc3, lambdafunc4):
...     return lambda x: lambdafunc1(x) * lambdafunc2(x) * lambdafunc3(x) * lambdafunc4(x)
...
>>> f = func_you(sum,min,max,sum)
>>> f([1,2])
18

This is definitely technically a nested function:

def func_you(lambdafunc1, lambdafunc2, lambdafunc3, lambdafunc4):
    def func_you_2(x):
        return lambdafunc1(x) * lambdafunc2(x) * lambdafunc3(x) * lambdafunc4(x)

    return func_you_2

But you could use a lambda too:

def func_you(lambdafunc1, lambdafunc2, lambdafunc3, lambdafunc4):
    return lambda x: lambdafunc1(x) * lambdafunc2(x) * lambdafunc3(x) * lambdafunc4(x)

The def -within- def structure is actually quite common. It's used to implement decorator functions , which take a function as an input, modify it somehow, and return the modified function. Basically, this structure:

@decorator
def func(param):
    # stuff

is the same as:

def func(param):
    # stuff

func = decorator(func)

For example, say you have several functions which you want to modify so that they print messages on entry and exit. You write a decorator function:

def mark_entry_and_exit(func):
    def inner(*args, **kwargs):
        print "Entering function."
        try:
            result = func(*args, **kwargs)
        except:
            print "Exiting with exception."
            raise
        print "Exiting function."
        return result
    return inner

Then to use it, you just use the @ notation above:

@mark_entry_and_exit
def my_function(a, b):
    print "Running with", a, b

my_function(1, b=2)

prints:

Entering function.
Running with 1 2
Exiting function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM