I have the code
options=["INFO", "WARNING", "DEBUG"]
for i in range(len(options)):
option=options[i]
__cMenu.add_command(
label="{}".format(option),
command=lambda: self.filter_records(column, option)
)
which creates and saves several lambdas that should capture different values of the local variable option
. However, when these lambdas get used, they all behave as though options
was set to "DEBUG"
, the last value it takes on in the loop.
I am guessing this has something to do with the garbage collection in that only the last option remains, but I cannot figure out how to avoid this.
Please read about minimal examples. Without reading your code, I believe you have run into a well known issue addressed in previous questions and answers that needs 2 lines to illustrate. Names in function bodies are evaluated when the function is executed.
funcs = [lambda: i for i in range(3)]
for f in funcs: print(f())
prints '2' 3 times because the 3 functions are identical and the 'i' in each is not evaluated until the call, when i == 2. However,
funcs = [lambda i=i:i for i in range(3)]
for f in funcs: print(f())
makes three different functions, each with a different captured value, so 0, 1, and 2 are printed. In your statement
__cMenu.add_command(label="{}".format(option),
command=lambda: self.filter_records(column, option))
add option=option
before :
to capture the different values of option
. You might want to rewrite as
lambda opt=option: self.filter_records(column, opt)
to differentiate the loop variable from the function parameter. If column
changed within the loop, it would need the same treatment.