简体   繁体   English

如何摆脱 exec()

[英]How to get rid of exec()

Is there a way to use something other than exec() and to make this shorter/look more pro?有没有办法使用 exec() 以外的东西并使这个更短/看起来更专业?

for list_ in lists_to_activate:
    for widget in list_:
        exec(
            '{1} = tk.Label({0}, text="{2}", background="{3}", fg="{4}", font={5})'.format(widget[0],
                                                                                           widget[1],
                                                                                           widget[2],
                                                                                           widget[3],
                                                                                           widget[4],
                                                                                           widget[5]))
        exec('{}.pack({})'.format(widget[1],
                                  widget[7]))
        exec('{0}.bind("<Button-1>", lambda event, self=self, object={0}: self.button(object, "{0}"))'.format(
            widget[1]))

        if widget[6] == 1:
            exec('{0}.bind("<Enter>", lambda event, self=self, object={0}: self.is_focus(object, True))'.format(
                widget[1]))
            exec(
                '{0}.bind("<Leave>", lambda event, self=self, object={0}: self.is_focus(object, False))'.format(
                    widget[1]))

This is how lists_to_activate looks like.这就是 lists_to_activate 的样子。 lists_to_activate is a list of lists lists_to_activate 是一个列表列表

HEADER_WLIST = [
                ['self.header_frame', 'self.title', 'EVIL MARKET ANALYZER', 'black', 'white', '("FuturaBookC", 21)', 0,
                 'side="left",padx=35,pady=13'],
                ['self.header_frame', 'self.settings', 'settings', 'black', 'white', '("FuturaLightC", 22)', 1,
                 'side="right",padx=20,pady=10'],
                ['self.header_menu', 'self.menu_1', '  TODAY  ', '#ff402f', 'white', '("FuturaBookC", 35)', 1,
                 'side="left", fill="both", expand = 1'],
                ['self.header_menu', 'self.menu_2', '   NEWS   ', 'white', 'black', '("FuturaBookC", 35)', 1,
                 'side="left",fill="both", expand = 1'],
                ['self.header_menu', 'self.menu_3', '  TWITTER ', 'white', 'black', '("FuturaBookC", 35)', 1,
                 'side="left", fill="both", expand = 1'],
                ['self.header_menu', 'self.blank', ' ', 'white', 'black', '("FuturaBookC", 0)', 0,
                 'side="left",pady=25'],
                ['self.header_menu', 'self.menu_4', 'CONCLUSION', 'white', 'black', '("FuturaBookC", 35)', 1,
                 'side="right", fill="both", expand = 1']
]
CNBC_WLIST = []...

Thank you in advance:)先感谢您:)

Warning of exec or eval execeval警告

Whenever you use exec or eval , you should reconsider what you're doing, as those functions should almost never be used.每当你使用execeval时,你应该重新考虑你在做什么,因为这些函数几乎不应该被使用。 Using them indicates a severe design flaw as code and data becomes the same thing, when they should be separated.使用它们表明存在严重的设计缺陷,因为代码和数据在应该分开时变成了同一件事。 Code is logic, and data is data.代码就是逻辑,数据就是数据。

If you start coding using either of those functions, it's going to be hard to change your design afterwards.如果您开始使用其中任何一个功能进行编码,那么之后将很难更改您的设计。 So avoid them from the beginning!所以从一开始就避免它们!

What to do instead该怎么做

It's hard to know the solution for your specific problem, so I had to guess.很难知道您的具体问题的解决方案,所以我不得不猜测。 But this shouldn't be too different from what you could do.但这与您可以做的事情并没有太大的不同。

First, create a class that contains the actual data you want to operate on, with good names.首先,创建一个 class ,其中包含您要操作的实际数据,并具有良好的名称。 This makes things clearer as you'll write widget.text instead of widget[2] .这使事情变得更清楚,因为您将编写widget.text而不是widget[2]

class Widget:
    def __init__(self, text, background, foreground, font, config, is_focusable):
        self.text = text
        self.background = background
        self.foreground = foreground
        self.font = font
        self.config = config
        self.is_focusable = is_focusable

Then create a function that encapsulates the logic, ie the common operations, and pass in the relevant data.然后创建一个封装了逻辑即常用操作的function,并传入相关数据。

def create_label(frame, widget, parent):
    label = tk.Label(frame, text=widget.text, background=widget.background, fg=widget.foreground, font=widget.font)
    label.pack(**widget.config)
    label.bind("<Button-1>", lambda event, self=parent, object=label: self.button(object, label.__name__))

    if widget.is_focusable:
        label.bind("<Enter>", lambda event, self=parent, object=label: self.is_focus(object, True))
        label.bind("<Leave>", lambda event, self=parent, object=label: self.is_focus(object, False))
    
    return label

Store the data in a proper data structures.将数据存储在适当的数据结构中。 It seems like you're trying to create labels for some frame.您似乎正在尝试为某个框架创建标签。 Using a dictionary allows you to associate a name (like the name of your attribute) with some data.使用字典允许您将名称(如属性名称)与某些数据相关联。

WIDGET_LIST = [
    'title':    Widget('EVIL MARKET ANALYZER', 'black', 'white', '("FuturaBookC", 21)', False, {'side': "left", 'padx': 35, 'pady': 13}),
    'settings': Widget('settings', 'black', 'white', '("FuturaLightC", 22)', True, {'side': "right", 'padx': 20, 'pady': 10})
    # And so on...
]

Then you can do iterate over the dictionary and use our function to create labels.然后您可以遍历字典并使用我们的 function 创建标签。 This assumes that you use a dictionary self.labels instead of individual attributes like self.title , self.menu_1 , self.settings , and so on...这假设您使用字典self.labels而不是self.titleself.menu_1self.settings等单个属性...

for name, widget in WIDGET_LIST.items():
    self.labels[name] = create_label(self.header_menu, widget, self)

Full code完整代码

class Widget:
    def __init__(self, text, background, foreground, font, config, is_focusable):
        self.text = text
        self.background = background
        self.foreground = foreground
        self.font = font
        self.config = config
        self.is_focusable = is_focusable


WIDGET_LIST = [
    'title':    Widget('EVIL MARKET ANALYZER', 'black', 'white', '("FuturaBookC", 21)', False, {'side': "left", 'padx': 35, 'pady': 13}),
    'settings': Widget('settings', 'black', 'white', '("FuturaLightC", 22)', True, {'side': "right", 'padx': 20, 'pady': 10})
    # And so on...
]


def create_label(frame, widget, parent):
    label = tk.Label(frame, text=widget.text, background=widget.background, fg=widget.foreground, font=widget.font)
    label.pack(**widget.config)
    label.bind("<Button-1>", lambda event, self=parent, object=label: self.button(object, label.__name__))

    if widget.is_focusable:
        label.bind("<Enter>", lambda event, self=parent, object=label: self.is_focus(object, True))
        label.bind("<Leave>", lambda event, self=parent, object=label: self.is_focus(object, False))
    
    return label

# Then use this in your class which contains the different labels, don't have this globally.
for name, widget in WIDGET_LIST.items():
    self.labels[name] = create_label(self.header_menu, widget, self)

You could use getattr and setattr :您可以使用getattrsetattr

for list_ in lists_to_activate:
    for widget in list_:
        cur_wid = tk.Label(getattr(self, widget[0].replace("self.", "")), text=widget[2], background=widget[3], fg=widget[4], font=widget[5])
        cur_wid.pack(widget[7])
        cur_wid.bind("<Button-1>", lambda event, self=self, object=cur_wid: self.button(object, widget[1]))

        if widget[6] == 1:
            cur_wid.bind("<Enter>", lambda event, self=self, object=cur_wid: self.is_focus(object, True))
            cur_wid.bind("<Leave>", lambda event, self=self, object=cur_wid: self.is_focus(object, False))
        setattr(self, widget[1].replace("self.", ""), cur_wid)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM