I simply cannot understand what is happening here. The problem is important for my homework (studying programming so I'm a beginner... also my English is not that good, sorry).
I am trying to read a string... it can be either a number or a set number of commands.
I'll just give a very small example of what I'm trying to do and what is going wrong.
def validate():
choice = str(input(">>> "))
if (choice == "exit"):
return 0 # should exit validate
else:
try:
aux = int(choice) # Tries converting to integer
except:
print("Insert integer or exit")
validate() # If it can't convert, prompts me to try again through
# recursivity
else:
return aux
rezult = validate()
print (rezult)
Problem is that this small script returns totally random stuff.
If "exit", returns "None".
If first input is correct, it returns correct number.
If first input is an "error" and second input is correct, it's "None" again and I simply can't understand what is going wrong... Why it doesn't want to work or what should I do (alternatively).
In case you enter the except block, the function validate() uses a recursive call to call itself. When this call returns, it returns to the place where the function was called, i.e. into the except block. The return value of validate() is ignored at this point, and control reaches the end of the outer call without hitting a return statement, so None is implicitly returned.
Don't use recursion here. Use a loop.
Use raw_input instead of input (unless you are on Python 3.x):
choice = raw_input(">>> ")
And you are missing a return here:
except:
print ("Insert integer or exit")
return validate () # <<< here
Also, don't use recursion for this. Use a loop instead.
Ok, decided to listen and changed the recursive part into a loop, thank you for your help. (Works now)
def validateChoice():
condition = False
while (condition == False):
choice = str (input (">>> "))
if (choice == "exit"):
return 0
else:
try:
aux = int (choice)
except:
print ("Insert integer or 'exit'")
else:
condition = True
return aux
Related
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!
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.
I have worked on many projects (school projects, I'm not too advanced), and have found that in many programs where I require the user to input a value that is an integer, or decimal(float), I need to use a "try-except" statement, within a while loop, in order to make certain that the user inputs the required value type.
For example:
def main():
userValue = input("Please enter an integer: ")
while(True):
try:
userValue = int(userValue)
break
except:
userValue = input("That is not an integer, try again: ")
print("The integer you entered is: " + str(userValue))
main()
# Input: SADASD (A non-integer value)
# Output: "That is not an integer, try again: "
# Second-Input: 3
# Second-Output: "The integer you entered is: 3"
Understandably, typing out this entire section of code repeatedly, in a program that requires user input multiple times, is not really efficient. So understanding, that user-defined functions help when I need to perform one action, multiple times. With this in mind, I defined my own function with that same try-except statement in a while loop. However, now, when I use the function, instead of printing the same output previously, rather, it prints out the first value the user had input.
For example:
def valueCheck_Integer(userInput):
while(True):
try:
userInput= int(userInput)
break
except:
userInput = input("That is not an integer, try again: ")
def main():
userValue = input("Please enter an integer: ")
valueCheck_Integer(userValue)
print("The integer you entered is: " + str(userValue))
main()
# Input: SADASD (A non-integer value)
# Output: "That is not an integer, try again: "
# Second-Input: SASASD
# Second-Output: "That is not an integer, try again: "
# Third-Input: 3
# Third-Output: SADASD (The first value that the user Input, instead of 3)
Can someone please explain to me why this happens, and some suggestions on how to fix it?
Thank you!
It's probably going to be easier to expect the function to get/check/return the integer rather than check input you already have. You can pass it the string to use for asking for the value (you could also pass the error string). It will keep asking until it's successful and then return the number you want:
def get_integer(question):
while(True):
try:
return int(input(question))
except ValueError:
question = "That is not an integer, try again:"
def main():
userValue = get_integer("Please enter an integer: ")
print("The integer you entered is: " + str(userValue))
main()
It is because of you are printing userValue instead of userInput.
I used return make it easier. So the code will be like this
def valueCheck_Integer(userInput):
while(True):
try:
userInput= int(userInput)
break
except:
userInput = input("That is not an integer, try again: ")
return userInput
def main():
userValue = input("Please enter an integer: ")
print("The integer you entered is: " + str(valueCheck_Integer(userValue)))
main()
You can make your code smaller like this:
def valueCheck_Integer(userInput):
while not(userInput.isdigit()):
userInput = input("That is not an integer, try again: ")
return userInput
def main():
userValue = input("Please enter an integer: ")
print("The integer you entered is: " + str(valueCheck_Integer(userValue)))
main()
First off, Good Question.
To understand what is going on, we first have to talk about scope of a variable.
When you define a variable outside a function, it becomes something called a global variable. This basically means that you can access it from anywhere in your code. When you define the variable within a function, it becomes a local variable. This means that it is only accessible from within your function. Finally, when a function gets passed in a variable, it gets its own local copy of the variable to work with.
Now let's look at your code.
when you call valueCheck_Integer(userInput): the function gets its own copy of userInput to work with. thus all the changes that the function does modifies the local userInput while the global userInput stays the same. As such, when the user enters a correct answer, the global userInput is the one that gets printed and the changes the function makes to local userInput is lost.
So, how can we fix this?
There are two main methods:
1)Using the global keyword
def valueCheck_Integer(userInput):
global userInput
while(True):
try:
userInput= int(userInput)
break
except:
userInput = input("That is not an integer, try again: ")
This keyword asks the function to modify the global userInput
2)Returning a value
def valueCheck_Integer(userInput):
while(True):
try:
userInput= int(userInput)
break
except:
userInput = input("That is not an integer, try again: ")
return userInput
def main():
userValue = input("Please enter an integer: ")
print("The integer you entered is: " + str(valueCheck_Integer(userValue)))
main()
This works by returning the local copy of userInput and modifying global userInput to equal local userInput
The second code I used was from
Osadhi Virochana Jayasinghe Si's answer.
It's because, if you see your line of code where you print the final output -:
print("The integer you entered is: " + str(userValue))
you will realise that the value you are printing is the one you take the first time from the input function. But this is not the value you have been working on to achieve in your other function.
So for you to rather get that value, the function in some way has to return it back to you.
For this you should allow the function to return the value in the last line.
like so -:
return userInput
and then change the line where you call function so it saves the value returned.
like so -:
userValue = valueCheck_Integer(userValue)
Also as mentioned by others using the global keyword you can define the variable in global scope.
But this is really not a good practice until really needed as it can increase the amount of space that the var is taking, before the variable only took the space for a limited time for when the function is called, but now the variable takes space throughout the time the program runs.
While return will not do so as it will only return the value and once assigned to the already defined variable it will remove the returned value from space.
This should hopefully fix your problem.
I hope this helps.
And also hope that you're safe during the time of this ongoing pandemic.
I'm a beginer in Python and I do not succeed to figure out how to solde the issues in my code. As my lecture do not provide any assistance, according to the online module that became mandatory because of the corona, I really need your help !
Before to go on the issues, there is the goals of my code :
The first function take as arguments 2 integers, and returns a random number between those integers. We will call this function get_rand_int. If the two integers are equals, this is an error and we will return None. (Hint: just put return None as your line for these cases.) We can test for the result of None in the second function and report that it was an error there.
The second function, called print_random, asks for user input for one integer greater than 0, and if it receives good input, calls the first function. It converts the user input to an integer and calls the first function with 0 as the first argument and the user input as the second argument. We capture the output from the first function in a variable (e.g., rand = get_rand_int(0, input)). Our second function then prints out the number returned by the first function in a sentence: "Your random number is " and then the number.
For now, I think my code is in line with the goal ( just need to add something in the case of the first functiun would return "none") but I'm stuck with a small error which is making me stuck ! This error occurs when I'm trying to run the second function !
File "<ipython-input-83-f6b07c49d323>", line 2
def print_random():
^
SyntaxError: unexpected EOF while parsing
My code
import random
def get_rand_int(arg1, arg2):
rand = random.randint(arg1, arg2)
if float(rand) == float(arg1):
return None
elif float(rand) == float(arg1):
return None
else:
print(rand)
def print_random():
try :
prompt = int(input("Please enter an integer greater than 0:"))
assert(prompt > 0)
except:
print("Invalid input: You must input an integer greater than 0 for your input.")
rand = get_rand_int(0, input)
print( "Your random number is ",rand)
Thanks for your help !
You had two mistakes that were not terribly obvious. You tried passed the input function to your get_rand_int method and you forgot to return the rand value. Complete working code below:
import random
def get_rand_int(arg1, arg2):
rand = random.randint(arg1, arg2)
if float(rand) == float(arg1):
return None
elif float(rand) == float(arg1):
return None
else:
print(rand)
return rand # You need to return the random value
def print_random():
try :
prompt = int(input("Please enter an integer greater than 0:"))
assert(prompt > 0)
except:
print("Invalid input: You must input an integer greater than 0 for your input.")
rand = get_rand_int(0, prompt) # You need to pass in the value return from input, not input func
print( "Your random number is ", rand)
So I have a while true loop -
while True:
getStatus()
print('Ended')
I hope to be able to break out of it if answer is 999. this is what I tried:
def getStatus():
answer = input('What is the box ID? ')
if answer == 999:
return False
elif type(answer) == int:
boxId = answer + 1
print(boxId)
However even when the input is '999' it loops back and asks 'What is the box ID? ' again.
How do I get out of the while true loop?
Your while loop keeps looping because that's exactly what you've told it to do. After the function you call from its body returns, you ignore the return value, unconditionally print "Ended" and then do it all again, since the condition on the loop is obviously still truthy.
If you want the function to control if the loop keeps going, you should use its return value as the condition in the loop, with something like this:
running = True
while running:
running = getStatus()
print("Ended") # move this outside the loop!
This requires that getStatus returns a truthy value when you want to keep looping and a falsey value when you want to stop. Your current implementation of that function doesn't do that. It returns False when 999 is entered, but doesn't explicitly return anything if you give other input (which in Python is equivalent to returning None). Since both False and None are falsey, the code above won't actually work (you could patch it with something like running = getStatus() is None, but that would be horrible). You should change the function to have an explicit return statement in all of its branches (including the case for non-integer inputs, where it doesn't go into either your if or elif blocks).
If the loop and the function's logic are tightly intertwined, it might make sense to move the loop into the function itself, rather than having it be separate and needing to use a return value to signal when to stop. In a single function, you can use break to exit a loop directly:
def getStatus():
while True:
answer = input('What is the box ID? ')
if answer == 999:
break
elif isinstance(answer, int): # isinsance() is better than type(...) == ...
boxId = answer + 1
print(boxId)
else:
print("I'm sorry, I didn't understand that.") # still good to handle this case
you can add if statement before get_status() that will check if it's true and break and in the get_status function you will have to return true to break
def getStatus():
answer = input('What is the box ID? ')
if answer == 999:
return True
elif type(answer) == int:
boxId = answer + 1
print(boxId)
while True:
if getStatus():
print('Ended')
break
def selectedCountry():
while True:
country = input("Enter country of which you want to check pictures HR, RS, RO: ").upper()
if country == str("HR") or country == str("RO") or country == str("RS"):
break
else:
print("Please enter HR or RO or RS: " + "you wrote: " + country)
Why while True is working outside of a function and inside the same problem with asking again
Enter country of which you want to check pictures HR, RS, RO: >? hr
Enter country of which you want to check pictures HR, RS, RO:
You may change it to -
while True:
if(getStatus()==False):
print('Ended')
break
By this you can use returned value to break out of infinite loop.
I'm just trying Python, and really like it! But I get stucked with try/except.
I have a code that checks raw_input for being integer, but i'd like to make it function, and it doesn't want to be it :)
here the code, I have this:
number_of_iterations = raw_input("What is your favorite number?")
try:
int(number_of_iterations)
is_number = True
except:
is_number = False
while not is_number:
print "Please put a number!"
number_of_iterations = raw_input("What is your favorite number?")
try:
int(number_of_iterations)
is_number = True
except:
is_number = False
I don't want to repeat myself here& So I think smth about to make function:
def check_input(input_number):
try:
int(input_number)
return True
except:
return False
But it make an error if input a string, saying that int can't be used for strings. Looks like it does not see 'try' keyword.
Can smone explain why it happens and how to prevent it in future?
Try this, it avoids repeating yourself without needing a def
while True:
try:
number_of_iterations = int(raw_input("What is your favorite integer?"))
break
except ValueError:
print "Please put an integer!"
EDIT: Per the suggestions of the commenters, I have added break to the try portion of the block to eliminate the else (the original remains as a reference below). Also, I changed "number" to "integer" because "3.14" would be invalid in the above code.
This was my original suggestion. The above is fewer lines (some may call this cleaner), but I prefer the below because to me the intent is clearer.
while True:
try:
number_of_iterations = int(raw_input("What is your favorite integer?"))
except ValueError:
print "Please put an integer!"
else:
break
If you want it as a function, decide two things:
What is it going to need to work, and
What it's going to need to spit back out.
Your use case is that you need some sort of int back, and if it bombs out for whatever reason, it's defined as not a number.
Let's create a tuple as our return value, so we can return a number of some kind and a boolean for "if it is a number".
def check_input(number):
try:
return (int(number), True)
except ValueError:
return (-999999, False) # Care more about boolean here
We can then use that return value in our while loop like so. Note that I explicitly set the loop condition to False, so we enter in at least once.
is_number = False
num = -999999 # Define out of scope of loop so it can be used
while not is_number:
print "Please put a number!"
num, is_number = check_input(raw_input("What is your favorite number?"))
The line num, is_number is a result of tuple packing. Since we're returning a tuple from our method, we can set two distinct variables to the results of that tuple.