0

I have a dummy_calcurve.csv file with parameters for a set of calibration curves as follows:

repeat,method,slope,intercept
a,linear,2,3
b,linear,4,5

I want to get a calcurve : dict of lambda-functions from this, such that I can calibrate for condition 'a' as follows: y=calcurve['a'](x).

I did the following:

calcurve = {}
ccs = pd.read_csv('dummy_calcurve.csv', index_col=0)
for repeat in ccs.index:
    slope = ccs.slope[repeat]
    intercept = ccs.intercept[repeat]
    print(repeat, slope, intercept)
    calcurve[repeat] = lambda x : slope * x + intercept
print(calcurve['a'](0))
print(calcurve['b'](0))
>>> a 2 3
>>> b 4 5
>>> 5
>>> 5

I would expect the final outputs to be 3 and 5. In other words, both calibration curves appear to be the second one (for b), while the intermediate print statements suggest otherwise.

What am I missing here?

Ben Zeen
  • 72
  • 7
  • 1
    Does this answer your question? [What do lambda function closures capture?](https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture) and [Creating functions (or lambdas) in a loop (or comprehension)](https://stackoverflow.com/q/3431676/4046632) – buran Sep 15 '22 at 07:58
  • 1
    Also [Why do lambdas defined in a loop with different values all return the same result?](https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result) – buran Sep 15 '22 at 08:00
  • This is very interesting! This is apparently normal behavior. I will read into your links. Thanks a lot! – Ben Zeen Sep 15 '22 at 08:05

1 Answers1

0

EDIT 1

When adding the following, it works as expected.

def calibration(slope, intercept):
    return lambda x : slope * x + intercept

calcurve = {}
ccs = pd.read_csv('dummy_calcurve.csv', index_col=0)
for repeat in ccs.index:
    slope = ccs.slope[repeat]
    intercept = ccs.intercept[repeat]
    print(repeat, slope, intercept)
    calcurve[repeat] = calibration(slope, intercept)
>>> print(calcurve['a'](0))
>>> print(calcurve['b'](0))
>>> a 2 3
>>> b 4 5
>>> 3
>>> 5

I do not understand why this makes any difference.

EDIT 2 The following also fixes the issue.

calcurve = {}
ccs = pd.read_csv('dummy_calcurve.csv', index_col=0)
for repeat in ccs.index:
    slope = ccs.slope[repeat]
    intercept = ccs.intercept[repeat]
    print(repeat, slope, intercept)
    calcurve[repeat] = lambda x, s=slope, i=intercept : s * x + i
print(calcurve['a'](0))
print(calcurve['b'](0))

>>> a 2 3
>>> b 4 5
>>> 3
>>> 5

According to the official Python docs, this is global/local scope issue. The slope and intercept parameters are not local to the lambda and thus are being updated everywhere during every loop. By making an extra variable i and s, these do become local. For the same reason, adding another layer with the calibration-function, which makes the slope and intercept local as well, fixes the issue as well.

Ben Zeen
  • 72
  • 7