lambda function of another function but force fixed argument
Asked Answered
L

3

11

I just switched to Python from Matlab, and I want to use lambda function to map function f1(x,y) with multiple arguments to one argument function f2(x) for optimization. I want that when I map the function f2(x) <- f1(x,y=y1) then y will stay constant no matter what y1 changes, in Matlab this is true by default but if I try in Python, it keeps changing as the following examples

>>> def f1(x,y):
>>>    return (x+y)
>>> y1 = 2
>>> f2 = lambda x: f1(x,y1)
>>> f2(1)
3

I expect f2(1) stays 3 even if I change y1, however if I change y1, the whole f1(1) also changes as follows

>>> y1 = 5
>>> f2(1)
6

I wonder is there a way that when I declare f2 = lambda x: f1(x,y1) then f1 will take the value of y1 at that time and fix it to f2. The reason for this because I want to dynamically create different functions for different scenarios then sum them all. I'm still new to Python, please help, much appreciate.

Lopsided answered 21/9, 2016 at 1:3 Comment(0)
T
14

Try:

f2 = lambda x, y=y1: f1(x,y)

Your issue has to do with how closures work in Python

Your version of the lambda function will use the current version of y1. You need to capture the value of y1 on the line where you've defined the lambda function. To do that, you can define it as the default value of a parameter (the y=y1 part).

Tableau answered 21/9, 2016 at 1:6 Comment(1)
it now works as I want, thanks for the tip, I feel like it is kinda a trick as f2 actually still has two arguments, but it also takes 1 argument hence works for my caseLopsided
A
1

As already pointed out, your issue comes down to how closures work. However, you really shouldn't be using a lambda for this - lambdas are for anonymous functions. Make a higher-order function with def statements instead:

>>> def f1(x,y):
...   return x + y
... 
>>> def f1_factory(y):
...   def f1_y(x):
...     return f1(x,y)
...   return f1_y
... 
>>> f1_factory(6)(4)
10
>>> f1_factory(5)(4)
9

It also avoids the problem you encountered:

>>> y = 3
>>> newfunc = f1_factory(y)
>>> newfunc(1)
4
>>> y = 20
>>> newfunc(1)
4
>>> 

From PEP8:

Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.

Yes:

def f(x): return 2*x

No:

f = lambda x: 2*x

The first form means that the name of the resulting function object is specifically 'f' instead of the generic <lambda>. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)

Appointed answered 21/9, 2016 at 1:10 Comment(2)
I always use @ function in Matlab, I thought lambda function in Python is exactly same thing. I will keep this in mind for future coding, thanks a lot for the adviceLopsided
@JoseVu It's more a matter of style, really. Both of these are anonymous functions. But the style in Python is that if your anonymous function isn't going to be, well, anonymous, then just use a full function definition statement.Appointed
H
0

The most elegant and modern solution is to use functools.partial. In your case:

>>> from functools import partial
>>> def f1(x,y):
>>>    return (x+y)
>>> y1 = 2
>>> f2 = partial(f1, y=y1)
>>> f2(1)
3
>>> y1 = 5
>>> f2(1)
3
Hallowed answered 21/7, 2024 at 20:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.