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.

Asked By: Lindsey

||

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
Answered By: Karoly Horvath

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))
Answered By: Daniel

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.

Answered By: Marcin
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.