Python 使用eval()动态生成Tkinter子顶级类
我想知道这个例子是否足以作为在python中使用备受诟病的eval()函数的借口 我制作了一个选择弹出窗口的基类。因为这个循环在我的程序中是一个很常见的主题,所以我从中继承它来创建各种选择窗口。机场、飞机、人员等。。。我只是更改它显示的信息和用于查询数据库的查询,我将其作为变量传入(为了简化,这里不显示) 正如您在下面看到的,我传入了一个“返回变量”的名称,该变量将在确认选择并成功关闭子窗口时更新。我尝试过setattr(),但我无法摆脱它是一个字符串并抛出一个错误,所以我一直坚持使用eval()函数Python 使用eval()动态生成Tkinter子顶级类,python,tkinter,Python,Tkinter,我想知道这个例子是否足以作为在python中使用备受诟病的eval()函数的借口 我制作了一个选择弹出窗口的基类。因为这个循环在我的程序中是一个很常见的主题,所以我从中继承它来创建各种选择窗口。机场、飞机、人员等。。。我只是更改它显示的信息和用于查询数据库的查询,我将其作为变量传入(为了简化,这里不显示) 正如您在下面看到的,我传入了一个“返回变量”的名称,该变量将在确认选择并成功关闭子窗口时更新。我尝试过setattr(),但我无法摆脱它是一个字符串并抛出一个错误,所以我一直坚持使用eval(
#!/usr/bin/env python3
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master = None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.pack()
self.config(width = 400)
self.create_application()
def create_application(self):
self.label1 = tk.Label(self, text = "Label 1")
self.label1.pack()
self.entry1_string = tk.StringVar()
self.entry1 = tk.Entry(self, state = "readonly",
textvariable = self.entry1_string)
self.entry1.pack()
self.entry1_select = tk.Button(self, text = "Select...",
command = lambda: self.create_entry1_select_window())
self.entry1_select.pack()
self.label2 = tk.Label(self, text = "Label 2")
self.label2.pack()
self.entry2_string = tk.StringVar()
self.entry2 = tk.Entry(self, state = "readonly",
textvariable = self.entry2_string)
self.entry2.pack()
self.entry2_select = tk.Button(self, text = "Select...",
command = lambda: self.create_entry2_select_window())
self.entry2_select.pack()
def create_entry1_select_window(self):
self.entry1_select_window = AirportSelectWindow(self,
return_variable = "entry1_string")
self.entry1_select_window.title("Select Entry 1")
def create_entry2_select_window(self):
self.entry2_select_window = AirportSelectWindow(self,
return_variable = "entry2_string")
self.entry2_select_window.title("Select Entry 2")
class BaseSelectWindow(tk.Toplevel):
def __init__(self, master = None, return_variable = None, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.configure(padx = 10, pady = 10)
self.master = master
######### Is this ok?
self.return_variable_path = eval("self.master."+return_variable)
## Just for example. Real thing retrieves values from DB. ##
self.search_results = ["Heathrow", "O'Hare", "LAX", "Schipol"]
self.create_base_widgets()
def create_base_widgets(self):
self.selection_string = tk.StringVar()
self.selection_data = tk.OptionMenu(self, self.selection_string,
*self.search_results)
self.selection_data.pack()
self.selection_button = tk.Button(self, text = "Confirm...",
command = lambda: self.confirm_selection(self.selection_string))
self.selection_button.pack()
def confirm_selection(self, selection):
self.return_variable_path.set(selection.get())
self.destroy()
class AirportSelectWindow(BaseSelectWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def main():
root = tk.Tk()
root.title('Main Window')
app = Application(root)
app.mainloop()
if __name__ == "__main__":
main()
这很酷吗?它不是用户生成的值,因此应该是安全的。不,它不是
eval
的好用法。在这种情况下,eval
的唯一优点是使代码更难理解
显然,您希望将属性的名称发送给AirportSelectWindow
的构造函数,但是如果您只传入实际变量,代码将更容易理解
class BaseSelectWindow(tk.Toplevel):
def __init__(self, master = None, return_variable = None, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.return_variable_path=return_variable
...
然后,您可以这样创建它:
def create_entry1_select_window(self):
self.entry1_select_window = AirportSelectWindow(self,
return_variable = self.entry1_string)
但是,我将使用
self.return\u variable
而不是self.return\u variable
。我不认为路径增加了清晰度,事实上消除了一些清晰度。我还将self.entry1\u string
更改为self.entry1\u var
,因为变量表示StringVar
,而不是字符串(entry2也是如此)。不,这不是eval
的好用法。在这种情况下,eval
的唯一优点是使代码更难理解
显然,您希望将属性的名称发送给AirportSelectWindow
的构造函数,但是如果您只传入实际变量,代码将更容易理解
class BaseSelectWindow(tk.Toplevel):
def __init__(self, master = None, return_variable = None, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.return_variable_path=return_variable
...
然后,您可以这样创建它:
def create_entry1_select_window(self):
self.entry1_select_window = AirportSelectWindow(self,
return_variable = self.entry1_string)
但是,我将使用
self.return\u variable
而不是self.return\u variable
。我不认为路径增加了清晰度,事实上消除了一些清晰度。我还想将self.entry1\u string
更改为self.entry1\u var
,因为变量表示StringVar
,而不是字符串(entry2也是如此).为什么传递的字符串是属性名而不是实际属性?上面的代码段比我正在开发的实际代码要短得多。这是一个符合SO发布小型工作示例的政策的示例。我会尝试一下你下面的建议,然后再回来找你。我问的问题与上述代码无关,更多关于传递预期返回变量名的原理,以便我将来可以以相同的方式重用基类并节省代码。为什么要传递属性名而不是实际属性的字符串?上面的代码段比我正在开发的实际代码要短得多。这是一个符合SO发布小型工作示例的政策的示例。我会尝试一下你下面的建议,然后再回来找你。我问的问题与上面的代码无关,更多的是关于传递预期返回变量名的原理,这样我将来可以以同样的方式重用基类并节省代码。好的,你教了我一些东西。我不知道你可以穿过一个物体,它会“跟踪”它。我原以为当您传入“self.entry1_string”时,子窗口会尝试逐字调用它,您会得到一个“child object has not attribute'entry1_string'”错误,因此我尝试使用“self.master.*.widget*”调用它。我已经做了你建议的修改,效果很好,非常感谢。嗨,布莱恩,你能帮我更好地理解这一点吗?从python文档中我所记得的,我想我可以理解,当创建子窗口时,我是否正确地认为创建了一个新的名称空间?那么,当您将小部件传入返回变量时,它是否隐式地称为“self.master.*widget”?对象是否在两个名称空间中存在两个不同的引用,或者子窗口是否包含一个引用,有点像C中的指针?@pilky01:No,当您传入一个返回变量时,它不会隐式调用任何内容。在我的示例中,我显式地将参数命名为return\u variable
,并显式地将其保存为self.return\u variable\u path
。这些是参考资料。只有一个对象,有多个引用。谢谢你的回答。好的,你教会了我一些东西。我不知道你可以穿过一个物体,它会“跟踪”它。我原以为当您传入“self.entry1_string”时,子窗口会尝试逐字调用它,您会得到一个“child object has not attribute'entry1_string'”错误,因此我尝试使用“self.master.*.widget*”调用它。我已经做了你建议的修改,效果很好,非常感谢。嗨,布莱恩,你能帮我更好地理解这一点吗?从python文档中我所记得的,我想我可以理解,当创建子窗口时,我是否正确地认为创建了一个新的名称空间?那么,当您将小部件传入返回变量时,它是否隐式地称为“self.master.*widget”?对象是否在两个名称空间中存在两个不同的引用,或者子窗口是否包含一个引用,有点像C中的指针?@pilky01:No,当您传入一个返回变量时,它不会隐式调用任何内容。在我的示例中,我显式地将参数命名为return\u variable
,并显式地将其保存为self.return\u variable\u path
。这些是参考资料。只有一个对象,有多个引用。谢谢