+ 7
[Solved] on Python's lambda and closures.
def cm(): return[lambda x:i*x for i in range(3)] for m in cm(): print (m(1)) Output: 2 2 2 Why? I also tried different things like changing the range and argument for "m" and seems like it always outputs the last range item times the argument. For example: def cm(): return[lambda x:i*x for i in range(4)] for m in cm(): print (m('a')) Will output: aaa aaa aaa aaa I will be appreciated for your help. 🌹❤🙏
11 ответов
+ 5
Was checking up on it. Found these, thanks to Oma's response:
https://louisabraham.github.io/articles/JUMP_LINK__&&__python__&&__JUMP_LINK-lambda-closures.html
https://stackoverflow.com/questions/14514922/confused-by-lexical-closure-in-list-comprehension
There are more sites about closure, mainly it's a function nested inside another, being able to use a varible of the higher function as if a global variable("non local"), in this case, it's i. That explains it.
You ask great questions, imo. I always learn from them.
+ 5
I think something similar to this is happening in your code:
a = []
for i in range(3):
a.append(lambda x: i*x)
Notice two things here:
1) i value is 2 after iteration, (look at for loop and range)
2) "a" variable is a list and now consists of three anonymous functions.
take any function from list,
b = a[0]
and pass argument to it.
b(3)
> 6
Output is always a multiple of 2 because of the logic,
Remember, i is 2 and we have given the argument 3, and logic of anonymous function is:
>i * x
Therefore,
>2 * 3
> 6
Note: If you change 'i' later, it will be reflected in output, it is happening because of 'i' value, given to it by range function.
+ 5
Oh my god.
Really great information thank you guys, Korkunç the Terrible Frusciante Oma Falk Sandeep Vinit Sonawane
I appreciate your help.
This is really great community that I always learn from.
Love you guys.
Best regards. 🌹❤🙏
+ 3
It is a closure. The lambdas share the last value of i.
+ 1
Korkunç the Terrible Frusciante
I think what is happening is f(x), g(x) and h(x) don't get evaluated at the time of creation, they will only run when we call them with argument and at the time of calling them, i = 2
So, at i = 0,
f(x) ≠ 0 * x
instead, it is
f(x) = i * x
hence, cm ≠ [0, x, 2x] ... cm store the reference to these function defination.
...at the time of calling the function f with argument, i is equal to 2 because 2 is the last value given to i by range function in for loop.
Therefore,
f(x) = 2 * x
If we change the i before calling function f , it will be reflected in the output,
i = 3
then, f(x) will become:
f(x) = i * x
= 3 * x
Python does not evaluate the functions until they are called.
+ 1
but... wow...
that blows my mind. feels very counterintuitive.
so when func is defined at line A,
returned at line B,
called at line C,
C goes to A, but returns the whole comprehension as if the loop is done and finished,
Why, because i's aren't appended but in a comprehension?
I actually knew you meant this but I thought it couldn't be?
I am lost. Yeah, Python doesn't evaluate funcs until they're called but doesn't Python parse them line by line from left to right and top to bottom in a reading fashion?
Lol suddenly my questions myltiplied. I need to look all of this up some time unless the experts see it.
Thank you.
+ 1
Korkunç the Terrible Frusciante
comprehension is not the reason for this, it is the case of functions inside functions.
Inside cm() function there are anonymous functions and cm return list of these functions (all are same according to logic)
Not sure what do you mean by parse line by line from left to right or top to bottom!
I think python do evaluated line by line from top to bottom as it is an interpreted langauge!?
I am still a beginner and learning things. I have to say I really love python, it is simple and amazing :]
+ 1
it's like for each iteration i list_i= [2, 2, 2] because the loop is executed inside the comprehension first for each lambda, giving a single value(last one in range as Sandeep said in his first post), and then iterate x*i over list_i, like mapping, as far as I understand. now i is like this new indexing you have for this list, i_list[0 ] = i_list[1] = i_list[2]= 2(edit: for x = 1, each multiplied with x it becomes 2, 2, 2)
0
You need to do this
https://code.sololearn.com/c5JNq6Vcv2Bf/?ref=app
Refer : https://stackoverflow.com/a/34021333
0
Sandeep Can you elaborate on i being 2?
isn't cm() = [f(x), g(x), h(x)] where (ax would do but not losing the emphasis on these being iterations)
if i = 0,
f(x) = 0*x = 0
if i = 1,
g(x) = 1*x = x
if i = 2,
h(x) = 2*x = 2x
and cm = [0, x, 2x]
and when
for m=0 in cm,
f(1) = f(x) = 0
for m = x in cm,
g(1) = 1
for m = 2x in cm,
h(1) = 2*1 = 2,(edited, skipped arg)
and therefore
0
1
2
So this is how I don't get it either. It must have happened just as you said, I just don't get how (will have to run some errands, can't copy OP's code into the CP and play with it)
0
I was meaning operand evaluation order and it's said to be Python is a language of both (interpreter and hidden compiler) although I haven't read enough about it to know how ir factors in.
At some point when I call m(1), it tracks down how many takes it will be by iterating i, so you have three different values for one call or else theres'd be no iteration, yet in all of them i is the last value in range as if it was executed before. I'll do lsmbdas and LCs and composite func until I get it.
I don't think I could love this although I love almost everything I've learned so far about Python