2015-11-29 58 views
0

版问题:拉姆达在循环只需要最后一个值

上下文菜单应该动态显示过滤变量,并在回调中定义的参数执行的功能。 通用描述显示正确,但函数调用始终使用上次设置选项执行。

我曾尝试:

#!/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

无论哪三个我选择的选项。我认为它只能处理最后一个选项的垃圾回收,但我无法弄清楚如何避免这种情况。

建议任何帮助。

回答

4

请阅读关于minimal examples。如果没有阅读你的代码,我相信你遇到了一个众所周知的问题,在以前的问题和答案中需要2行来说明。当函数被执行时,函数体中的名字被评估。

funcs = [lambda: i for i in range(3)] 
for f in funcs: print(f()) 

打印“2” 3倍,因为3个功能是相同的,所述的“i”中的每个未评价,直到呼叫,当我== 2。然而,

funcs = [lambda i=i:i for i in range(3)] 
for f in funcs: print(f()) 

提出了三个不同的功能,每个功能都具有不同的捕捉值,因此打印0,1和2。在你的声明

__cMenu.add_command(label="{}".format(option), 
    command=lambda: self.filter_records(column, option)) 

:前添加option=option捕捉option不同的值。您可能需要重写为

lambda opt=option: self.filter_records(column, opt) 

以区分循环变量和函数参数。如果在循环内更改column,则需要进行相同的处理。