lambda function of another function but force fixed argument - python

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.

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

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)

Related

Can a function using a global variable use the variable's value from when the function was declared rather than when it was called?

Here is a very simplified example of what I am trying to do:
x = 3
def f():
print(x)
x = 5
f() #f prints 5 but I want it to print 3.
Is there a way, when declaring the function, to turn x into a constant that points somewhere other than the global variable x? I can't provide arguments to the function.
This is a pretty common trick (you usually see it in lambda expressions that want to bind a particular value within a loop):
x = 3
def f(x=x):
print(x)
x = 5
f() # prints 3
The trick is that default parameter values are evaluated at the time of function definition, so in the expression x=x, the x on the right hand side is evaluated (producing the value 3) and then stored as the default value of the x parameter in the function (which shadows the x in the outer scope).
You could equivalently write:
x = 3
def f(n=x):
print(n)
x = 5
f() # prints 3
which has the same result, but doesn't shadow the x variable.
From what I understand, you seem to want x to hold two values simultaneously - which is what complex data structures are for. A list would work fine, or a dict:
>>> x = [3]
>>> def f():
... print(x[0]) # always refers to first element. Functionally constant.
...
>>> x.append(5)
>>> f()
3
>>>
However, it sounds like you really have an XY problem, where you're asking about your solution instead of your actual problem. Go back to your code and check if this seems to be the case. If so, we might be able to point you towards a better way of solving your real issue.

What is the mechanism behind a function that contains a lambda expression? (Python)

During a tutorial I stumbled upon the following example.
I get the general purpose and mechanism of functions. They get parameters such as "a", "b" and "c" (example below).
But how come that we can "link" the function to an object f that itself can contain 0 as parameters that will then be computed by our lambda expression?
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
f(0)
yields:
-5
In layman words, how does the function "know" that 0 must be read by the lambda expression that is contained in the function?
Can somebody explain the mechanism behind it?
Thank you!
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x + c
is (in all important aspects) equivalent to
def build_quadratic_function(a,b,c):
def func(x):
return a*x**2 + b*x + c
return func
In both cases, the inner function, be it an anonymous one or not, is holding onto the variables in the enclosing scope. You have discovered so called closures.
>>> import inspect
>>> f = build_quadratic_function(2, 3, -5)
>>> inspect.getclosurevars(f)
ClosureVars(nonlocals={'a': 2, 'b': 3, 'c': -5}, globals={}, builtins={}, unbound=set())
A very similar example can be found in the documentation.
Lambdas are small anonymous functions. They can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda functions can reference variables from the containing scope.
Therefore if you define a custom function that contains a lambda, and then fix its parameters, it's essentially the same as defining a lambda function and then passing the expression.
For the sake of your example:
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
Would create the same output as:
f = lambda x: 2*x**2 + 3*x - 5
In either case, when you call f(0) then the expression gets evaluated with value 0 returning -5.
2*0**2 + 3*0 - 5 = - 5
The improvement using a custom function over the simple definition of the lambda itself is you can modify the a, b and c parameters.
This isn't a lambda specific thing. Its a "closure" and can be done with a regular function also. In fact, a lambda is just an anonymous function. Its it restricted to implementing an expression instead of full python statements, but that's only the case because of python parsing issues. So, this is the same thing
def build_quadratic_function(a,b,c):
def inner(x):
return a*x**2 + b*x+c
return inner
inner uses variables from the enclosing function. When build_quadratic_function returns inner, the current objects in a, b and c are bound to inner. Later, when inner(someval) is called, those bound objects to a, b and c are used. x, which is a parameter to inner needs to be supplied on each call.
You can get the inner function once and use it many times with the same values.
func = build_quadratic_function(1,2,3)
for i in range(10):
print(func(i))
A lambda function is a small anonymous function. (function with no name)
f = build_quadratic_function(2,3,-5)
Till this point, f is equal to the return value of build_quadratic_function, which is another function(lambda in this case)!
f(0) calls the lambda which is waiting

Lambda function containing if statement

Is there any way how to code recursive function containing if with lamba?
Is possible to rewrite this using lambda.
def factorial(x):
if x <= 1:
return 1
return x * factorial(x - 1)
print(factorial(5))
No, or at least not without assigning the function to a variable and then using that name to call it. But you still cannot use any statements in the function.
In any case, don't do that. A lambda function is exactly like a normal def function in Python besides the restriction that it cannot contain statements.
The only reason to use a lambda in Python is to avoid defining an named function if you just need a simple callable returning some value.
Yes, it is possible for this specific case.
>>> factorial = lambda x: 1 if x < 1 else x * factorial(x - 1)
>>> factorial(5)
120
I wouldn't recommend it though. A standard function definition seems far more readable to me.
>>> l = lambda i: 1 if i<=1 else i * l(i-1)
>>> l(5)
120
>>> 5*4*3*2*1
120

How to deepcopy a function object

I create a function which returns an value specified by an variable. Like
y = 1.
def f(x):
return y
I need this function as an function object to create another object
dist = dist.distribution(f, other_variables)
this works fine. But if i want to create several different distribution objects (with different functions f in the sense that y changes) Like
dist = dist.distribution(f, other_variables)
y = 2.
dist2 = dist.distribution(f, other_variables)
Then all distribution objects only return the last specified value y. I.e.
dist.f()(1.)
>>>> 2.
dist2.f()(1.)
>>>> 2.
Instead of the expected
dist.f()(1.)
>>>> 12.
dist2.f()(1.)
>>>> 2.
The problem clearly is, that the function f accesses the variable only when it is called and not one time initially.
Is there a way around it?
What I want at the end is:
A function with one variable only (x, although this doesnt do anything in this case, it is needed in others), which returns the value of y of the moment, when the distribution is created. So in principle I want that at the initialisation of the distribution, the given function is deepcopyed, in the sense, that it is no longer influenced by any change of variables.
Is this possible?
Don't use globals for this. There is no need to 'deepcopy' the function either; the y global is not part of the function state at all.
Use a function factory that provides a scoped value instead, or use a functools.partial() to provide a default argument to your function.
Function factory:
def produce_f(y):
def f(x):
return y
return f
dist = dist.distribution(produce_f(1.), other_variables)
Now y is a scoped value for f, produce_f() returns a new f every time it is called, and y is stored as a cell variable for f.
Demo:
>>> f1 = produce_f(12.)
>>> f2 = produce_f(42.)
>>> f1('foo')
12.0
>>> f2('foo')
42.0
Using functools.partial():
from functools import partial
def f(y, x):
return y
dist = dist.distribution(partial(f, 1.), other_variables)
Here partial(f, 1.) produces a new callable that will call f(1., ...) whenever called, appending any extra arguments passed in.
Demo:
>>> f1 = partial(f, 12.)
>>> f2 = partial(f, 42.)
>>> f1('foo')
12.0
>>> f2('foo')
42.0

lambda returns lambda in python

Very rarely I'll come across some code in python that uses an anonymous function which returns an anonymous function...?
Unfortunately I can't find an example on hand, but it usually takes the form like this:
g = lambda x,c: x**c lambda c: c+1
Why would someone do this? Maybe you can give an example that makes sense (I'm not sure the one I made makes any sense).
Edit: Here's an example:
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
f(y,a[x][0]),f(x,a[x][1])))()
You could use such a construct to do currying:
curry = lambda f, a: lambda x: f(a, x)
You might use it like:
>>> add = lambda x, y: x + y
>>> add5 = curry(add, 5)
>>> add5(3)
8
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
f(y,a[x][0]),f(x,a[x][1])))()
See the () at the end? The inner lambda isn't returned, its called.
The function does the equivalent of
def swap(a, x, y):
a[x] = (a[x], a[y])
a[y] = a[x][0]
a[x] = a[x][1]
But let's suppose that we want to do this in a lambda. We cannot use assignments in a lambda. However, we can call __setitem__ for the same effect.
def swap(a, x, y):
a.__setitem__(x, (a[x], a[y]))
a.__setitem__(y, a[x][0])
a.__setitem__(x, a[x][1])
But for a lambda, we can only have one expression. But since these are function calls we can wrap them up in a tuple
def swap(a, x, y):
(a.__setitem__(x, (a[x], a[y])),
a.__setitem__(y, a[x][0]),
a.__setitem__(x, a[x][1]))
However, all those __setitem__'s are getting me down, so let's factor them out:
def swap(a, x, y):
f = a.__setitem__
(f(x, (a[x], a[y])),
f(y, a[x][0]),
f(x, a[x][1]))
Dagnamit, I can't get away with adding another assignment! I know let's abuse default parameters.
def swap(a, x, y):
def inner(f = a.__setitem__):
(f(x, (a[x], a[y])),
f(y, a[x][0]),
f(x, a[x][1]))
inner()
Ok let's switch over to lambdas:
swap = lambda a, x, y: lambda f = a.__setitem__: (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1]))()
Which brings us back to the original expression (plus/minus typos)
All of this leads back to the question: Why?
The function should have been implemented as
def swap(a, x, y):
a[x],a[y] = a[y],a[x]
The original author went way out of his way to use a lambda rather then a function. It could be that he doesn't like nested function for some reason. I don't know. All I'll say is its bad code. (unless there is a mysterious justification for it.)
It can be useful for temporary placeholders. Suppose you have a decorator factory:
#call_logger(log_arguments=True, log_return=False)
def f(a, b):
pass
You can temporarily replace it with
call_logger = lambda *a, **kw: lambda f: f
It can also be useful if it indirectly returns a lambda:
import collections
collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(int)))
It's also useful for creating callable factories in the Python console.
And just because something is possible doesn't mean that you have to use it.
I did something like this just the other day to disable a test method in a unittest suite.
disable = lambda fn : lambda *args, **kwargs: None
#disable
test_method(self):
... test code that I wanted to disable ...
Easy to re-enable it later.
This can be used to pull out some common repetitive code (there are of course other ways to achieve this in python).
Maybe you're writing a a logger, and you need to prepend the level to the log string. You might write something like:
import sys
prefixer = lambda prefix: lambda message: sys.stderr.write(prefix + ":" + message + "\n")
log_error = prefixer("ERROR")
log_warning = prefixer("WARNING")
log_info = prefixer("INFO")
log_debug = prefixer("DEBUG")
log_info("An informative message")
log_error("Oh no, a fatal problem")
This program prints out
INFO:An informative message
ERROR:Oh no, a fatal problem
It is most oftenly - at least in code I come accross and that I myself write - used to "freeze" a variable with the value it has at the point the lambda function is created. Otherwise, nonlocals variable reference a variable in the scope they exist, which can lead to undesied results sometimes.
For example, if I want to create a list of ten functions, each one being a multiplier for a scalar from 0 to 9. One might be tempted to write it like this:
>>> a = [(lambda j: i * j) for i in range(10)]
>>> a[9](10)
90
Whoever, if you want to use any of the other factoried functions you get the same result:
>>> a[1](10)
90
That is because the "i" variable inside the lambda is not resolved when the lambda is created. Rather, Python keeps a reference to the "i" in the "for" statement - on the scope it was created (this reference is kept in the lambda function closure). When the lambda is executed, the variable is evaluated, and its value is the final one it had in that scope.
When one uses two nested lambdas like this:
>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)]
The "i" variable is evaluated durint the execution of the "for" loop. ItÅ› value is passed to "k" - and "k" is used as the non-local variable in the multiplier function we are factoring out. For each value of i, there will be a different instance of the enclosing lambda function, and a different value for the "k" variable.
So, it is possible to achieve the original intent :
>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)]
>>> a[1](10)
10
>>> a[9](10)
90
>>>
It can be used to achieve a more continuation/trampolining style of programming,
See Continuation-passing style
Basically, with this you can modify functions instead of values
One example I stumbled with recently: To compute approximate derivatives (as functions) and use it as an input function in another place.
dx = 1/10**6
ddx = lambda f: lambda x: (f(x + dx) - f(x))/dx
f = lambda x: foo(x)
newton_method(func=ddx(f), x0=1, n=10)

Categories