Pythonic Logic - 寻求一种更有效的方法来处理检查 0 和 1 列表的多个 if 语句

Pythonic Logic - Seeking a more efficient approach to multiple if statements that check a list of 0's and 1's

我一直在 Python 中开发一个简单的 GUI 来从 PowerBi 中提取数据,它看起来类似于下图:

该应用运行良好,但我希望提高它的效率。

checkbar 使用以下代码生成:

Datasets = [
    'Option 1', 'Option 2', 'Option 3',
    'Option 4', 'Option 5',
    'Option 6', 'Option 7',
    'Option 8', 'Option 9']

print(os.getcwd())
cwd = os.getcwd

class Checkbar(Frame):
    def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
        Frame.__init__(self, parent)
        self.vars = []
        for pick in picks:
            var = IntVar()
            chk = Checkbutton(self, text=pick, variable=var, width=22, anchor='w')
            chk.pack(side=side, anchor=anchor, expand=YES)
            self.vars.append(var)
    def state(self):
        return map((lambda var: var.get()), self.vars)

if __name__ == '__main__':
    root = Tk()
    root.title("PowerBI Data Collector")
    root.iconphoto(True, PhotoImage(
        file="Icon/Directory"))
    responseLabel = Label(root)
    
    # Check
    data1 = Checkbar(root, Datasets[0:3], anchor=W)
    data2 = Checkbar(root, Datasets[3:6], anchor=W)
    data3 = Checkbar(root, Datasets[6:9], anchor=W)

    data1.grid(row = 3, column = 1, padx = 1, pady = 1)
    data1.config(relief=GROOVE, bd=1)
    data2.grid(row = 4, column = 1, padx = 1, pady = 1)
    data2.config(relief=GROOVE, bd=1)
    data3.grid(row = 5, column = 1, padx = 1, pady = 1)
    data3.config(relief=GROOVE, bd=1)

根据用户在复选框中的选择,生成一个 0 和 1 的列表来描述输入的状态,使用代码:

dataState = list(data1.state())
dataState.extend(list(data2.state()))
dataState.extend(list(data3.state()))

因此,如果选择选项 2 和选项 4,dataState 将显示为:[0,1,0,1,0,0,0,0,0]

从这里开始,有许多 if 语句检查列表中它们各自的整数是否为 1,如果是,则调用各自的函数从 PowerBi 中提取特定于该复选框的数据。下面详细介绍了其中的一些:

            if dataState == [0]*len(Datasets): # nothing
                responseLabel.destroy()
                responseLabel = Label(text = "Please select from the checklist above")
                responseLabel.grid(row = 7, column = 1)

            if dataState[0] == 1: # option2
                # Response Label
                responseLabel.destroy()
                try:
                    uf.option2(User=userDetails[0], Pass = userDetails[1])
                    responseLabel = Label(text = "All data downloaded")
                    responseLabel.grid(row = 7, column = 1)
                except:
                    responseLabel = Label(text = "option 1 data download failed")
                    responseLabel.grid(row = 7, column = 1)

            if dataState[1] == 1: # option1
                # Response Label
                responseLabel.destroy()
                try:
                    uf.option1(User=userDetails[0], Pass = userDetails[1])
                    responseLabel = Label(text = "All data downloaded")
                    responseLabel.grid(row = 7, column = 1)
                except:
                    responseLabel = Label(text = "option 2 data download failed")
                    responseLabel.grid(row = 7, column = 1)

这个效率很低,以前只有3个选项还好,现在有9个,希望能增加更多。我正在考虑将 if 语句部分转换为 for 循环,并且对应于列表中的 1 的循环迭代称为特定函数,但这似乎也很低效,所以我提出了在这里提问,希望能找到更好的建议。

谢谢!

我在 option1 和 option2 的 if 下看到的代码之间的唯一区别是被调用的函数:uf.option1 与 uf.option2 以及失败打印。这种代码重复是可以避免的。

首先,使用字典将选项与其在uf中的功能进行映射:

option_funcs={1: uf.option1, 2: uf.option2 ...}

然后将“if”中的代码转换为一个函数,该函数获取一个整数选项作为参数并调用相关的 uf.option

def download_data(option):
    responseLabel.destroy()
    try:
        option_funcs[option](User=userDetails[0], Pass = userDetails[1])
        responseLabel = Label(text = "All data downloaded")
        responseLabel.grid(row = 7, column = 1)
    except:
        responseLabel = Label(text = "option {} data download failed".format(option))
        responseLabel.grid(row = 7, column = 1)

最后,将所有 if 替换为遍历 dataState 的 for:

for count, value in enumerate(dataState, start=1):
    if value: download_data(count) 

一个简单的、可扩展的选项是将每个选项的代码变成一个函数并将它们放入 listtuple,例如:

optionFunc = (opt1, opt2, opt3, etc.)

然后您可以遍历 dataState 并调用关联的函数,例如:

for index, state in enumerate(dataState):
    if state:
        option_func[index](responseLabel)

可能有更复杂的方法来做到这一点,也许您使用的 GUI 代码可以将标签与您可以用作字典索引的复选框相关联,但这是一般的想法。

(我将 optionFunc 放在 camelCase 中以与您的其余代码保持一致,但在 Python 中 snake_case 将是首选形式)