4 ms·
I generally like coding with lambdas, but in Python one thing I hate is that they will capture a numeric loop index by ref and not by its current value. If you
by sixbrx 8y ago
I generally like coding with lambdas, but in Python one thing I hate is that they will capture a numeric loop index by ref and not by its current value. If you try generating some polynomials x -> x, x^2, x^3 ... in the "obvious" way you'll see what I mean, all polynomials will be the same as the last one after the loop or list compr is done.
Theres a workaround using default arg value to capture by val but its ugly and easy to forget and hard to "see" in review that its missing.
This is as much an issue of loops not generating "fresh" instances of their index vars as it is a problem with lambdas, to be fair, but it still sucks, esp in mathematical domains. Julia used to suffer from this but fixed it, I believe the same is true for C# too.
- bo1024 8y agoYes! This caused one of the trickier bugs I've had (the functions were supposed to be almost the same anyway, but ended up identical). I thought of it immediately when reading this article.
- istjohn 8y agoDo you mind fleshing out your example with some actual code? I'm not quite following, and I'm completely lost by the time you talk about the workaround.
- sixbrx 8y agoSure, what I meant by the "obvious" way of making some polynomials is: polys = [] for i in range(0,4): polys.append(lambda x: x**i) But that actually just yields the same polynomial x -> x^3 in each element of polys array: polys[0](2) > 8 polys[1](2) > 8 polys[2](2) > 8 The same thing happens if we use a list comprehension: polys = [lambda x: x**i for i in range(0,4)] The trick is to add a default argument value to the lambda, which catches "i" by value instead of by reference: for i in range(0,4): polys.append(lambda x, i=i: x**i) And now we get the different polynomials we expected: polys[0](2) > 1 polys[1](2) > 2 polys[2](2) > 4 polys[3](2) > 8