Я хотел бы узнать, является ли этот пример достаточно хорошим поводом для того, чтобы использовать столь ненавистную функцию eval() в python.

Я создал базовый класс всплывающего окна выбора. Поскольку этот цикл является довольно распространенной темой в моей программе, я наследую от него, чтобы создавать окна выбора для самых разных вещей. Аэропорты, самолеты, люди и так далее... Я просто изменяю отображаемую информацию и запрос, который он использует для обращения к базе данных, которые я передаю в качестве переменных (здесь не показаны для упрощения)

.

Как вы можете видеть ниже, я передаю имя "возвращаемой переменной", которая будет обновлена после подтверждения выбора и успешного закрытия дочернего окна. Я экспериментировал с функцией 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 = "Выбрать...",
                          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 = "Выбрать...",
                          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("Выбрать вход 1")
        
    def create_entry2_select_window(self):
        self.entry2_select_window = AirportSelectWindow(self,
                                             return_variable = "entry2_string")
        self.entry2_select_window.title("Выбрать вход 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
        ######### Это нормально?
        self.return_variable_path = eval("self.master."+return_variable)
        ## Просто для примера. Реальная вещь извлекает значения из БД. ##
        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 = "Подтвердить...",
               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('Главное окно')

    app = Application(root)
    app.mainloop()

if __name__ == "__main__":
    main()

Это круто? Это не пользовательское значение, поэтому оно должно быть безопасным.

pilky01

Ответов: 1

Ответы (1)

Нет, это не лучшее использование 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_variable_path я бы использовал self.return_variable. Я не вижу, что _path добавляет ясности, и на самом деле устраняет некоторую ясность. Я бы также изменил self.entry1_string на self.entry1_var, поскольку переменная представляет собой StringVar, а не строку (и то же самое для entry2).

2022 WebDevInsider