python lambda tkinter contextmenu

python - lambda en for loop solo toma el último valor



tkinter contextmenu (1)

Por favor, lea sobre ejemplos mínimos . Sin leer su código, creo que se ha topado con un problema bien conocido abordado en preguntas y respuestas anteriores que necesita 2 líneas para ilustrar. Los nombres en los cuerpos de las funciones se evalúan cuando se ejecuta la función.

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

imprime ''2'' 3 veces porque las 3 funciones son idénticas y la ''i'' en cada una no se evalúa hasta la llamada, cuando i == 2. Sin embargo,

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

realiza tres funciones diferentes, cada una con un valor capturado diferente, por lo que se imprimen 0, 1 y 2. En su estado de cuenta

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

agregar option=option antes : para capturar los diferentes valores de option . Es posible que desee reescribir como

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

para diferenciar la variable de bucle del parámetro de función. Si la column cambiara dentro del ciclo, necesitaría el mismo tratamiento.

Conjunto de problemas:

El menú contextual debe mostrar variables de filtro dinámicamente y ejecutar una función con parámetros definidos dentro de la devolución de llamada. Las descripciones genéricas se muestran correctamente, pero la llamada a la función siempre se ejecuta con la última opción establecida.

Lo que he intentado:

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

La salida actual que obtengo es:

Filtrar conjunto de registros de registro por 2 y DEPURAR

No importa cuál de las tres opciones elijo. Supongo que tiene algo que ver con la recolección de basura que solo queda la última opción, pero no puedo entender cómo evitar esto.

Se recomienda cualquier ayuda.