Search code examples
pythonperformancelogic

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


I've been working on a simple GUI within Python to pull data from PowerBi, that looks similar to the image below:

enter image description here

The app works fine, however I am looking to improve it's efficiency.

The checkbar is produced with the following code:

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)

Based on the user's choice's from the checkbars, a list of 0's and 1's is produced describing the state of the input, using the code:

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

As such, if option 2 and option 4 is chosen, the dataState will read: [0,1,0,1,0,0,0,0,0]

From here there are a number of if statements that check for whether their respective integers from the list is a 1, and if so calls the respective function to pull the data specific to that checkbox from PowerBi. A few of which are detailed below:

            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)

This is quite inefficient and was fine when there were only 3 options, but now there are 9, and more are expected to be added. I was thinking of converting the if statement section to a for loop, and the iteration of the loop that corresponded to a 1 within the list called a specific function, but this too seemed inefficient so I pose the question here, with the hopes of finding a better suggestion.

Thanks!


Solution

  • A simple, scalable option would be to make each option's code into a function and put them into a list or tuple, e.g.:

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

    Then you could iterate through dataState and call the associated function, something like:

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

    There may be a more sophisticated way to do this, maybe the GUI code you're using can associate labels with the checkboxes that you can use as dictionary indexes, but this would be the general idea.

    (I put optionFunc in camelCase to be consistent with the rest of your code, but in Python snake_case would be the preferred form)