How to define a function in a loop in Python
Question:
I’d appreciate it if anyone could help me with this issue (in Python). I have the function
f(x) = r*x*(1-x)
and I’d like to define it repeatedly for about 26 different values of r, ranging from 3.8 to 3.85 (I’d like to ultimately plot the cobweb plots for these functions and compare them, and I don’t want to have r as a parameter to my function). So I’d like to store these 26 functions within a list and then access them later. I have the following code, but instead of storing different function definitions, it only stores the function with the first value of r=3.8 in all 26 spots in the list.
r_list = []
r = 3.8
r_list.append(r)
for n in range(25):
new_r = round(r + 0.002, 3)
r_list.append(new_r)
r = new_r
f_t = []
for r in r_list:
f_t.append(lambda x: r*x*(1-x))
print r_list
print f_t
print f_t[0](3)
print f_t[2](3)
So my output for these print statements is:
[3.8, 3.802, 3.804, 3.806, 3.808, 3.81, 3.812, 3.814, 3.816, 3.818, 3.82, 3.822, 3.824, 3.826, 3.828, 3.83, 3.832, 3.834, 3.836, 3.838, 3.84, 3.842, 3.844, 3.846, 3.848, 3.85]
[<function <lambda> at 0x0000000008739908>, <function <lambda> at 0x0000000008739978>, <function <lambda> at 0x00000000087399E8>, <function <lambda> at 0x0000000008739A58>, <function <lambda> at 0x0000000008739AC8>, <function <lambda> at 0x0000000008739B38>, <function <lambda> at 0x0000000008739BA8>, <function <lambda> at 0x0000000008739C18>, <function <lambda> at 0x0000000008739C88>, <function <lambda> at 0x0000000008739CF8>, <function <lambda> at 0x0000000008739D68>, <function <lambda> at 0x0000000008739DD8>, <function <lambda> at 0x0000000008739E48>, <function <lambda> at 0x0000000008739EB8>, <function <lambda> at 0x0000000008739F28>, <function <lambda> at 0x0000000008739F98>, <function <lambda> at 0x0000000008739828>, <function <lambda> at 0x000000000873D048>, <function <lambda> at 0x000000000873D0B8>, <function <lambda> at 0x000000000873D198>, <function <lambda> at 0x000000000873D208>, <function <lambda> at 0x000000000873D278>, <function <lambda> at 0x000000000873D2E8>, <function <lambda> at 0x000000000873D358>, <function <lambda> at 0x000000000873D128>, <function <lambda> at 0x00000000165452E8>]
-23.1
-23.1
And I tried all of the suggestions from How can I define functions in a for loop?, but I still can’t get it to work. Any ideas? I’d really appreciate it.
Answers:
for r in r_list:
f_t.append(lambda x: r*x*(1-x))
Lambdas don’t capture the value, they capture the variables. Here the r
is the same in all lambdas, and its value is the last value it took in the loop.
You can fix it by manually capturing the value:
f_t.append(lambda x,r=r: r*x*(1-x))
Small example demonstrating the behaviour:
l=[1, 2, 3]
l2=[]
for r in l:
l2.append(lambda: r)
l2[0]() # 3
l2=[]
for r in l:
l2.append(lambda r=r: r)
l2[0]() # 1
The r
inside the lambda function is the r
of the outer context, so it has the value at the time, the function is called. To avoid this, localize r
:
f_t.append(lambda x, r=r: r*x*(1-x))
I don’t want to have r
as a parameter to my function
Why not?
it only stores the function with the first value of r=3.8 in all 26 spots in the list.
That doesn’t sound right. What it should be doing is capturing the variable r
, and it should have the value that r
has from time to time.
What you want to do is define your lambda like so:
for r in r_list:
f_t.append(lambda x, r=r: r*x*(1-x))
This way, the r
local to the lambda is assigned the value the external r
has at the time of definition.
I’d appreciate it if anyone could help me with this issue (in Python). I have the function
f(x) = r*x*(1-x)
and I’d like to define it repeatedly for about 26 different values of r, ranging from 3.8 to 3.85 (I’d like to ultimately plot the cobweb plots for these functions and compare them, and I don’t want to have r as a parameter to my function). So I’d like to store these 26 functions within a list and then access them later. I have the following code, but instead of storing different function definitions, it only stores the function with the first value of r=3.8 in all 26 spots in the list.
r_list = []
r = 3.8
r_list.append(r)
for n in range(25):
new_r = round(r + 0.002, 3)
r_list.append(new_r)
r = new_r
f_t = []
for r in r_list:
f_t.append(lambda x: r*x*(1-x))
print r_list
print f_t
print f_t[0](3)
print f_t[2](3)
So my output for these print statements is:
[3.8, 3.802, 3.804, 3.806, 3.808, 3.81, 3.812, 3.814, 3.816, 3.818, 3.82, 3.822, 3.824, 3.826, 3.828, 3.83, 3.832, 3.834, 3.836, 3.838, 3.84, 3.842, 3.844, 3.846, 3.848, 3.85]
[<function <lambda> at 0x0000000008739908>, <function <lambda> at 0x0000000008739978>, <function <lambda> at 0x00000000087399E8>, <function <lambda> at 0x0000000008739A58>, <function <lambda> at 0x0000000008739AC8>, <function <lambda> at 0x0000000008739B38>, <function <lambda> at 0x0000000008739BA8>, <function <lambda> at 0x0000000008739C18>, <function <lambda> at 0x0000000008739C88>, <function <lambda> at 0x0000000008739CF8>, <function <lambda> at 0x0000000008739D68>, <function <lambda> at 0x0000000008739DD8>, <function <lambda> at 0x0000000008739E48>, <function <lambda> at 0x0000000008739EB8>, <function <lambda> at 0x0000000008739F28>, <function <lambda> at 0x0000000008739F98>, <function <lambda> at 0x0000000008739828>, <function <lambda> at 0x000000000873D048>, <function <lambda> at 0x000000000873D0B8>, <function <lambda> at 0x000000000873D198>, <function <lambda> at 0x000000000873D208>, <function <lambda> at 0x000000000873D278>, <function <lambda> at 0x000000000873D2E8>, <function <lambda> at 0x000000000873D358>, <function <lambda> at 0x000000000873D128>, <function <lambda> at 0x00000000165452E8>]
-23.1
-23.1
And I tried all of the suggestions from How can I define functions in a for loop?, but I still can’t get it to work. Any ideas? I’d really appreciate it.
for r in r_list:
f_t.append(lambda x: r*x*(1-x))
Lambdas don’t capture the value, they capture the variables. Here the r
is the same in all lambdas, and its value is the last value it took in the loop.
You can fix it by manually capturing the value:
f_t.append(lambda x,r=r: r*x*(1-x))
Small example demonstrating the behaviour:
l=[1, 2, 3]
l2=[]
for r in l:
l2.append(lambda: r)
l2[0]() # 3
l2=[]
for r in l:
l2.append(lambda r=r: r)
l2[0]() # 1
The r
inside the lambda function is the r
of the outer context, so it has the value at the time, the function is called. To avoid this, localize r
:
f_t.append(lambda x, r=r: r*x*(1-x))
I don’t want to have
r
as a parameter to my function
Why not?
it only stores the function with the first value of r=3.8 in all 26 spots in the list.
That doesn’t sound right. What it should be doing is capturing the variable r
, and it should have the value that r
has from time to time.
What you want to do is define your lambda like so:
for r in r_list:
f_t.append(lambda x, r=r: r*x*(1-x))
This way, the r
local to the lambda is assigned the value the external r
has at the time of definition.