Want to know how lamda function work in python [duplicate] - python

This question already has answers here:
Lambda in a loop [duplicate]
(4 answers)
Closed 10 months ago.
I'm trying to understand the lambda function in python and got this.
When I store the instance of lambda function in a Dict. It gives the expected result inside of the loop. But outside of the loop, it always stored the last instance, I think.
Can someone explain why this happening? and how the lambda function actually works when we store their instance.
Code:
d = {}
for x in range(4):
d[x] = lambda n: str(n*x)
print(d[x](1))
print(d[1](2))
print(d[2](2))
print(d[3](2))
Output:
0
1
2
3
6
6
6

given some x these 2 functions are equivalent:
f1 = lambda n: str(n * x)
def f2(n):
return str(n * x)
all you are doing in addition to that is to put several functions (for several values of x) in a dictionary.

Related

List Comprehensions, Scoping and Lambdas in Python [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 2 years ago.
Let's say I want a family of functions f[0], f[1], ... f[9] such that f[y](x) = x + 2 * y.
To achieve this, I try the following list comprehension:
fs = [(lambda x : x + 2 * y) for y in range(10)]
However, this does not work at all. For example, fs[0](2) evaluates to 20, instead of the desired 4.
What is going on here? Is this some strange scoping issue?
I have also tried things like [(lambda x: x + 2 * y) for y in the list(range(10))] but none of this helps.
y may be the last value it was set to
Set it as a default argument to the lambda
[(lambda x, _y=y : x + 2 * _y) for y in range(10)]

How do I append a lambda to a list in python? [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I am trying to make a program that creates a list of lambda functions of the format y=mx+b, where 'm' and 'b' are predetermined values
My overall goal is to implement a function that
Takes a picture
Finds the lines on it
Extends them across the whole picture in a solid colour
Basically, something like a Hough transforms if you know what that is.
Once I have the lines for a specific image, I can create a lambda function to represent the slope of the line and where it begins. I'm having an issue not being able to append a lambda function to the list.
I have tried this :
if __name__ == "__main__":
nums = []
for i in range(10):
j = lambda x: x + i
nums.append(j)
for i in nums:
print(i(1))
Here is the error I'm getting :
Traceback (most recent call last):
File "C:/Users/me/.PyCharmCE2018.3/config/scratches/scratch_3.py", line 7, in <module>
print(i(1))
File "C:/Users/me/.PyCharmCE2018.3/config/scratches/scratch_3.py", line 4, in <lambda>
j = (lambda x: x + i)
TypeError: unsupported operand type(s) for +: 'int' and 'function'
The problem is that the lambdas you create are referring to the current value of i in the active stack frame. When you later reuse i for the second for loop, it is bound to the lambdas in your list. When invoked as i(1), the lambdas are trying to evaluate 1 + i where i is the lambda, so of course you get an error.
Probably what you want is to freeze the value of i at the point at which the lambda is created. You can do this by replacing:
j = lambda x: x + i
with:
j = (lambda y: lambda x: x + y)(i)
This effectively captures the current value of i by binding it to a lambda variable, then immediately applying that lambda, after which the binding remains fixed.
This will give you a clue:
>>> i=1
>>> a=lambda x:x+i
>>> a(5)
6
>>> i=2
>>> a(5)
7
lambda uses i in the outer scope. In the OP case, all the functions are the same. Using i in the final loop makes i a function, not an integer. Change it to something else, and you'll find the functions are all the same, using the last value of i:
nums = []
for i in range(10):
j = lambda x: x + i
nums.append(j)
for f in nums:
print(f(1))
10
10
10
10
10
10
10
10
10
10
The fix is, make i a parameter to the function, to capture the value as a local variable:
nums = []
for i in range(10):
j = lambda x,i=i: x + i
nums.append(j)
for f in nums:
print(f(1))
1
2
3
4
5
6
7
8
9
10
Your value of i has changed and it's not what you think.
First you create lambda:
j = lambda x: x + i
in hope, that i will remain as CURRENT value (so 0, 1, 2 and so on).
Then you execute it:
print(i(1))
Do you see, how you named your second iterator variable i? Change it to j and your example will work. Why? Because python resolves value of i in your lambda, when you execute it, not when you define it. So when you execute your lambda (i(1)) it will go to your lambda body and try x + i. Then it will lookup i, which now contains your lambda (not the INTEGER!). Hence your problem.
You need to do double function to make it work properly. Try this:
if __name__ == "__main__":
nums = []
for i in range(10):
def generate_lambda(i):
return lambda x: x + i
j = generate_lambda(i)
nums.append(j)
for i in nums:
print(i(1))
Why does this work? When you call generate_lambda, there will be i variable with your INTEGER value. It will shadow variable i used later on to iterate over lambdas. And since you never modify i variable inside generate_lambda function, it will stay like this forever.
I think you need to learn something more about lambda functions...
Actually, it's syntax is like : [lambda arguments: expression]
So, the issue is you have two variables in the expression, so you need to pass two arguments.
I don't really get what you want to achieve by this function, but I guess you need to have two arguments for m and b.
In your code, you need to initialize x and pass it as an argument to lambda.
nums = []
x=0
for i in range(10):
j = lambda x,i : x + i
nums.append(j)
for i in nums:
print(i(1,1))
You can use operator.add and functools.partial and do not lambda at all:
import operator
import functools
if __name__ == "__main__":
nums = []
for i in range(10):
nums.append(functools.partial(operator.add, i))
for i in nums:
print(i(1))

Defining Anonymous functions by list Comprehension [duplicate]

This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 4 years ago.
I am in need of creating functions (a lot) and storing inside an array or list. I tried using list comprehensions for generating functions (like the code shown below, indeed a simple case).
f = [lambda x: x*i for i in range(0,3)]
which gives
f[0](1) = 2 # expected 0
f[1](1) = 2 # expected 1
f[2](1) = 2 # expected 2 (no prblm with last case)
But instead of using iterators (like list comprehensions) to generate functions, if I write functions explicitly inside a list(defining each function), it works fine.
So, is there anything wrong with the above code(which uses iterators to generate anonymous functions)?
I believe this variant of the syntax will give you what you want:
f = [lambda x, i=n: x * i for n in range(0, 3)]
EXAMPLES
>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2
>>>
I believe what #user2357112 is leading you towards is the variation:
from functools import partial
f = [partial(lambda x, i: x * i, i=n) for n in range(0, 3)]
which may not be easy to tease out of the cited duplication page.
The inside of your lambda function is evaluated when you call the function, not when you create the function. At this point point the value of i is 2. You can verify this by running:
>>> f = [lambda x: x*i for i in range(0,3)]
>>> i
2
As cdlane pointed out in his answer, you can fix this by storing the values from the range() statement into a default parameter on your lambda function:
>>> f = [lambda x, i=i: x*i for i in range(0,3)]
>>> f[0](1)
0
>>> f[1](1)
1
>>> f[2](1)
2
This works because unlike the function body, the function definition is evaluated when you create the function.

Using list expansion for a set of lambda functions produces different results than the equivalent without list expansion [duplicate]

This question already has answers here:
Local variables in nested functions
(4 answers)
What do lambda function closures capture?
(7 answers)
Callback function tkinter button with variable parameter [duplicate]
(2 answers)
Closed 5 years ago.
I'm using list expansion to create a set of lambda functions. Each lambda function returns a generator with an initial value. The API I am using requires that I pass it a 0-parameter function handle that returns a generator object. Hence the odd form of lambda: generator.
I get unexpected results, shown below. Can anyone explain why I only see the generator seeded with 200 when using list expansion?
All code is copy/paste runnable.
Case 1: Using list expansion
def mygen(val):
for i in range(3):
yield val + i
generators = [lambda: mygen(start) for start in [100, 200]]
g = generators[0]() # generators[1]() produces the same result
for _ in range(3):
print(next(g))
Result:
200
201
202
Expected Result:
100
201
202
Case 2: Without list expansion
def mygen(val):
for i in range(3):
yield val + i
g0 = lambda: mygen(100)
g1 = lambda: mygen(200)
g = g0()
for _ in range(3):
print(next(g))
Result (as expected)
100
101
102

Converting a method with 2 variables to one variable [duplicate]

This question already has answers here:
Pass a function as a variable with one input fixed
(4 answers)
Closed 5 years ago.
I have a function foo that takes 2 arguments a and b. I want to create a list of functions that are similar to foo, but value of a is fixed.
def foo(a,b):
return a*b
fooList = []
for i in range(n):
fooList.append(foo(i))
I want fooList[i] to return a function that is similar to foo(i, b).
You can use functools.partial:
from functools import partial
def foo(a, b):
return a * b
fooList = []
for i in range(n):
fooList.append(partial(foo, i))
Then you'd do fooList[i](5) to calculate i * 5.
You can also curry lambda functions, somewhat like this:
for i in range(n):
fooList.append((lambda x: lambda y: x * y)(i))
You can then call that the same way as above.

Categories