List Comprehensions, Scoping and Lambdas in Python [duplicate] - python

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

Related

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

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.

How does Python know I want to double number I did not define? (Beginner) [duplicate]

This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 2 years ago.
x = 10
def double(y):
return 2 * x
print(double(x))
Output is 20
As far as I know, it should return None because in function "double" I double x which is undefined that block.
x is defined outside of the function scope as a global variable that is also available in the function
It is because x is a global variable, so when you call double it is just multiplying x by 2 no matter what
if you were to say put
x = 10
def double(y):
return 2 * x
print(double(40))
you would still get 20 as you are returning the variable x multiplied by 2.

How to use an if condition inside a list comprehension? [duplicate]

This question already has answers here:
if/else in a list comprehension
(12 answers)
Closed 3 years ago.
I have a reduce function that looks like this:
reduce(lambda x, y: x + y, [foo(x) for x in listValue], [])
I also have another function called goo and I want to use it when x achieves some condition, for example x >= 10 inside the reduce .
My idea is something like:
reduce(lambda x, y: x + y, [foo(x) for x in listValue if x < 10 else goo(x)], [])
but that gives me an error:
File "<stdin>", line 1
reduce(lambda x, y: x + y, [foo(x) for x in listValue if x < 10 else goo(x)], [])
^
SyntaxError: invalid syntax
How to solve this?
for and if are in the wrong order. You first need to specify the if, then the for.
Use this reduce in your code:
reduce(lambda x, y: x + y, [(foo(x) if x < 10 else goo(x)) for x in listValue], [])

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.

list of lambdas in python [duplicate]

This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I have seen this question, but i still cannot get why such simple example does not work:
mylist = ["alice", "bob", "greta"]
funcdict = dict(((y, lambda x: x==str(y)) for y in mylist))
funcdict['alice']("greta")
#True
funcdict['alice']("alice")
#False
funcdict['greta']("greta")
#True
How is it different from:
[(y, y) for y in mylist]
Why y is not evalueated within each step of iteration?
The y in the body of the lambda expression is just a name, unrelated to the y you use to iterate over mylist. As a free variable, a value of y is not found until you actually call the function, at which time it uses whatever value for y is in the calling scope.
To actually force y to have a value at definition time, you need to make it local to the body via an argument:
dict((y, lambda x, y=z: x == str(y)) for z in mylist)
((y, lambda x: x==str(y)) for y in mylist)
y inside the lambda is not bound at the time of the genration expression defined, but it's bound when it's called; When it's called, iteration is already done, so y references the last item greta.
One way to work around this is to use keyword argument, which is evaluated when the function/lambda is defined:
funcdict = dict((y, lambda x, y=y: x == y) for y in mylist)
funcdict = {y: lambda x, y=y: x == y for y in mylist} # dict-comprehension
or you can use partial:
funcdict = {y: partial(operator.eq, y) for y in mylist}
y is evaluated while the mylist is iterated.

Categories