My Password generator on tkinter is overusing the if/elif and i'm looking for alternatives

71 Views Asked by At

Im new to python and tkinter and was wondering a better alternative to the if/elif statements. This is not the most efficient code but I just wanted to know what can work with .get() when the conditions are constantly different

def generate(password):
    display_box.delete(0, END)
    password = ""
    password_length = password_scale.get()
    password_count = 0
    while password_count < password_length:
        #If all options are selected
        if (lower_var.get() == 1) & upper_var.get() == 1 & symbols_var.get() == 1:
            password += random.choice(
                uppercase_option + lowercase_option + symbol_option
            )
            password_count += 1
        #Upper and lower
        elif (lower_var.get() == 1) & (upper_var.get()):
            password += random.choice(uppercase_option + lowercase_option)
            password_count += 1
        #Lower and symbols
        elif (lower_var.get() == 1) & (symbols_var.get() == 1):
            password += random.choice(lowercase_option + symbol_option)
            password_count += 1
        #upper and symbols
        elif (upper_var.get() == 1) & (symbols_var.get() == 1):
            password += random.choice(uppercase_option + symbol_option)
            password_count += 1
        #Lower only
        elif lower_var.get() == 1:
            password += random.choice(lowercase_option)
            password_count += 1
        #Upper only
        elif upper_var.get() == 1:
            password += random.choice(uppercase_option)
            password_count += 1
        #symbols only
        elif symbols_var.get() == 1:
            password += random.choice(symbol_option)
            password_count += 1
        else:
            password_count += 1

    display_box.insert(0, password)
2

There are 2 best solutions below

0
acw1668 On BEST ANSWER

You just need to construct the character list once based on the selected categories and generate the password using the constructed character list:

def generate():
    sources = [lowercase_option, uppercase_option, symbol_option]
    selections = [lower_var.get(), upper_var.get(), symbols_var.get()]
    # construct the character list based on selected categories
    choices = ''.join(x for x, selected in zip(sources, selections) if selected)
    # generate the password
    passwd = ''.join(random.choice(choices) for _ in range(password_scale.get()))
    # show the generated password
    display_box.delete(0, "end")
    display_box.insert("end", passwd)
2
JRiggles On

Here are a few points for efficiency and reduced repetition:

  • I would recommend storing the values of your vars at the start of generate, rather than calling get() for each conditional branch.

  • You could also look into match case if you're using Python >= 3.10.

  • You can use if whatever_var.get() without the == 1.

  • You'd typically use the keyword and rather than & unless your specifically doing bitwise comparison.

  • You can ditch the else clause and just do password_count += 1 at the end of generate since every branch ends up incrementing this counter; this way you only need to do it once

With all that said, here's a (totally different) possible solution that changes the available choices depending on the user's selections by leveraging extend

def generate(password):
    display_box.delete(0, END)
    password = ""
    password_length = password_scale.get()
    password_count = 0
    # use 'extend' to modify the list of 'choices' as needed
    choices = []
    if upper_var.get():
        choices.extend(uppercase_option)
    if lower_var.get():
        choices.extend(lowercase_option)
    if symbols_var.get():
        choices.extend(symbol_option)
    # this way, if the user deselects an option, its items simply won't show up
    # as a 'choice', and you only need to call 'choice' once!
    
    while password_count < password_length:
        try:
            password += random.choice(choices)
        except IndexError:
            print('Please select an option')
            break
        else:  # increment the counter at the end
            password_count += 1
    display_box.insert(0, password)