for循环中的lambda仅取最后一个值 [英] lambda in for loop only takes last value

查看:686
本文介绍了for循环中的lambda仅取最后一个值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题集:

上下文菜单应动态显示过滤器变量,并使用在回调内部定义的参数执行函数. 通用描述可以正确显示,但始终使用最后设置的选项执行函数调用.

Context Menu should show filter variables dynamically and execute a function with parameters defined inside the callback. Generic descriptions show properly, but function call is always executed with last set option.

我尝试过的事情:

#!/usr/bin/env python

import Tkinter as tk
import ttk
from TkTreectrl import MultiListbox

class SomeClass(ttk.Frame):
    def __init__(self, *args, **kwargs):
        ttk.Frame.__init__(self, *args, **kwargs)
        self.pack(expand=True, fill=tk.BOTH)

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.View=MultiListbox(self)

        __columns=("Date","Time","Type","File","Line","-","Function","Message")
        self.View.configure(columns=__columns, expandcolumns=(0,0,0,0,0,0,0,1))

        self.View.bind("", self.cell_context)
        self.View.grid(row=0, column=0, sticky=tk.NW+tk.SE)

        self.__recordset          = []
        self.__recordset_filtered = False

        #Some dummy values
        self.__recordset.append(["Date", "Time", "INFO", "File", "12", "-", "Function", "Message Info"])
        self.__recordset.append(["Date", "Time", "DEBUG", "File", "12", "-", "Function", "Message Info"])
        self.__recordset.append(["Date", "Time", "WARNING", "File", "12", "-", "Function", "Message Info"])

        self.__refresh()

    def cleanView(self):
        self.View.delete(0, tk.END)

    def __refresh(self):
        self.cleanView()
        for row in self.__recordset:
            self.View.insert(tk.END, *row)

    def filter_records(self, column, value):
        print("Filter Log Recordset by {column} and {value}".format(**locals()))
        # Filter functionality works as expected
        # [...]

    def cell_context(self, event):
        __cMenu=tk.Menu(self, tearoff=0)

        if self.__recordset_filtered:
            __cMenu.add_command(label="Show all", command=lambda: filter_records(0, ""))

        else:
            column=2
            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))
            # Also tried using for option in options here with same result as now
        __cMenu.post(event.x_root, event.y_root)

if __name__=="__main__":
    root=tk.Tk()
    app=SomeClass(root)
    root.mainloop()

我得到的当前输出是:

按2和DEBUG过滤日志记录集

Filter Log Recordset by 2 and DEBUG

无论我选择三个选项中的哪个.我认为这与垃圾收集有关,只有最后一个选项仍然存在,但我无法弄清楚如何避免这种情况.

No matter which of the three options i choose. I assume it has sth to do with the garbage collection 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())

打印'2'3次,因为这3个函数是相同的,并且当i == 2时直到调用之前,每个函数中的'i'都不会求值.

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())

具有三个不同的功能,每个功能具有不同的捕获值,因此将打印0、1和2.在您的声明中

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))

:之前添加option=option以捕获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)

区分循环变量和功能参数.如果column在循环中更改,则将需要相同的处理.

to differentiate the loop variable from the function parameter. If column changed within the loop, it would need the same treatment.

这篇关于for循环中的lambda仅取最后一个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆