[Random String Generator]Getting stuck in a loop on else condition

151 Views Asked by At

So (as you will probably see from my code) I am a beginner at Python (version 3.8.3) and enjoying it very much so far, and I have challenged myself on several different beginner projects. I am currently making a random string generator (i.e. a password generator, hence the use of the secrets module).

# Password Generator
import secrets, string

print("Welcome to the generator. Please specify your requirements")
print("A. All Characters;\nB. No Numbers;\nC. No Punctuation\nPlease choose the appropriate letter for your needs.")
userInput = input()
def userWelcome():

  if userInput.lower() == "a":
      generatePass = string.ascii_letters + string.digits + string.punctuation
      print("How long do you want your string to be?")
      stringRange = int(input())
      print( "".join(secrets.choice(generatePass) for _ in range(stringRange)) )


  elif userInput.lower() == "b":
      generatePass = string.ascii_letters + string.punctuation
      print("How long do you want your string to be?")
      stringRange = int(input())
      print("".join(secrets.choice(generatePass) for _ in range(stringRange)))


  elif userInput.lower() == "c":
      generatePass = string.ascii_letters + string.digits
      print("How long do you want your string to be?")
      stringRange = int(input())
      print("".join(secrets.choice(generatePass) for _ in range(stringRange)))


  else:
      print("Not an option! Let's try again.")
      userWelcome()

userWelcome()

However, my problem is what to do if the user inputs an incorrect option. As you can see, with the else statement I assume what they filled in does not match any of the earlier options - and so I want to try to rerun the generator again (so I try to call userWelcome again in the else statement).

However, when I type in for example 12 as input, my shell starts to output my string (Not an option Let's try again) literally a thousand times like it is stuck in a loop. I am wondering what I am doing wrong exactly.

What I have tried:

(1) So I have tried to solve this input problem first with try and except, running the except when there is a ValueError but that only works for numbers and I did not manage to rerun userWelcome()

(2) I have tried to create a elif statement in which I check the input for integers, however that also gets stuck in a loop. Code:

elif userInput.isalpha() == False:
    print("Not an option! Let's try again.")
    userWelcome()

Anyway, I hope that explains it well. I have been busy with this for a few hours now and I thought I'd ask this. Maybe it's a very stupid question but for me it's hard :)

TL;DR: Want to check for proper user input by running my function again, get stuck in weird loop

Thank you for your time and effort!

1

There are 1 best solutions below

2
On BEST ANSWER

The code calls userWelcome() recursively, without changing the global variable userInput. The same bad string is processed again, causing the same result, which again calls userWelcome() - for ever (at least until max call depth).

You should read a new string at the beginning of userWelcome, instead of using a global variable. Also, recursion here is an overkill that confuses you. Better use a simple while loop:

while True:
  userInput = ....
  if ....
     do something
     return
  elif ...
     do something else
     return  # exit the function - breaking out of the loop
  else:
     print(error message)
     # No return here, means the loop will continue to loop
  

If you want to call the function instead of loop inside, you can instead make the function return success (True) vs. failure (False), and loop that in the caller:

while not userWelcome(inputString):
    inputString = read the string

def userWelcome(inputString):
   if inputString == ....:
      something
      return True # To mark OK
   elif inputString == .....:
      something else
      return True # To mark OK
   else:
      print an error
      return False # To mark failure

Just avoid global variables, it is a bad practice. Pass the value through parameters, as in the code above.