I am writing some scientific python code. At some point in the code I need to accept a list of callable objects (existing_functions
), and then produce another list of callable objects (changed_functions
) by injecting a change-of-variables in the original objects' __call__
methods. To me, the following seems like a nice abstraction.
import numpy as np
changed_functions = [lambda x: f(np.exp(x)) for f in existing_functions]
I worry about misusing lambda
here. So I ran some simple tests involving lambda
in loops and generator expressions. Those simple tests produced confounding results, which seem to involve variable-scope or pass-by-reference issues which I cannot decipher.
The code snippet below tries four different methods to define a list of anonymous functions using lambda
. Only the first method (with a list literal) works as I would hope.
# attempt 1: use a list literal
funcs = [lambda: 1, lambda: 2]
print(funcs[0]()) # 1
print(funcs[1]()) # 2
# attempt 2: much closer to my actual use-case.
gunks = [lambda: i for i in [1,2]]
print(gunks[0]()) # 2, but I expect 1.
print(gunks[1]()) # 2, as expected.
# attempt 3: an ugly version of my use case, which I thought might work.
hunks = [(lambda: i,)[0] for i in [1,2]]
print(hunks[0]()) # 2, but I expect 1.
print(hunks[1]()) # 2, as expected.
# attempt 4: another ugly version of my use case. "WE NEED MORE LAMBDA."
yunks = [(lambda: lambda: i)() for i in [1,2]]
print(yunks[0]()) # 2, but I expect 1.
print(yunks[1]()) # 2, as expected.
I am hoping that someone can explain to me why the last three methods in the snippet above all produce such a different result, compared to a list-literal.