Python: Recursion, I keep getting the wrong value, what I can do? - python

def answer():
if True:
ans = raw_input('Enter y/n:')
if ans != "y" and ans != "n":
print "Try again"
answer()
elif ans == "n":
return False
elif ans == "y":
return True
if answer():
print "It's working!, you entered Y"
else:
print "You entered N"
When I execute this code, I press Enter several times or enter wrong letters, then I enter y, I always get "You entered N" instead of "It's working!, you entered Y" .
I can't figure out what's the problem, please help me.

You are discarding the return value of your function in the if block. You should change it to:
if ans != "y" and ans != "n":
print "Try again"
return answer()
If you don't return the value, your function will return None, which will be evaluated as False on the outer if. Also, there is no need of if True: inside your function.
P.S: Please avoid using recursion for this task. You can easily do this with a while loop, which iterates till the user doesn't pass correct input, and breaks as soon as succeeds. Also, give user a certain number of attempts to pass correct inputs, to avoid infinite loop.

You don't really need recursion in this case, just use an infinite loop and don't return if the answer is not "y" or "n":
def answer():
while True:
ans = raw_input('Enter y/n:')
if not ans or ans not in "yn":
print "Try again"
else:
return ans == "y" # This is more succinct
if answer():
print "It's working!, you entered Y"
else:
print "You entered N"

Related

Exiting a program from an If/ELSE statement with Python

I am attempting to exit a program without using sys.exit()
The user is asked whether they wish to continue and if they input "Yes" a message saying so is printed and the program continues to run. If they input anything else a message saying they chose to exit is printed and then the program is meant to exit.
def keep_going():
answer = raw_input("Do you wish to continue?")
if answer == "yes":
print "You have chosen to continue on"
else:
print "You have chosen to quit this program"
What I am struggling with is what to add to ELSE to return something to my main which will cause the program to exit and how to go about writing that in code.
If you are so much keen about not using sys.exit() you could directly use raise SystemExit. Well this exception is technically raised when you call sys.exit() explicitly. In this way you don't need to import sys at all.
def keep_going():
answer = raw_input("Do you wish to continue?")
if (answer == "yes"):
print ("You have chosen to continue on")
else:
print "You have chosen to quit this program"
raise SystemExit
This answer will give you the alternate possible ways.
Try this:
def main():
while keep_going():
keep_going()
def keep_going():
answer = raw_input("Do you wish to continue?")
if answer == "yes":
print "You have chosen to continue on"
return True
else:
print "You have chosen to quit this program"
return False
if __name__ == "__main__":
main()
The program will continue calling keep_going() as long as it returns true, that is when a user answers "yes"
An even shorter solution would be to call keep_going() after the "yes" condition:
def keep_going():
answer = raw_input("Do you wish to continue?")
if answer == "yes":
print "You have chosen to continue on"
keep_going()
else:
print "You have chosen to quit this program"
Just, return something, and if that is returned, then let your main function exit, either by falling off the end, by using a return statement, or calling sys.exit()/raise SystemExit.
As an example, I'm here returning a string (a different one based on what the user answered):
def keep_going():
answer = raw_input("Do you wish to continue?")
if answer == "yes":
print "You have chosen to continue on"
return "keep going"
else:
print "You have chosen to quit this program"
return "please exit"
Now, in main, I can test which of these strings keep_going() returned:
def main():
while keep_going() != 'please exit':
# your code here
if __name__ == "__main__":
main()
While strings will work for this purpose, other values are more commonly used for such a task. If keep_going() returned True (instead of "keep going") or False (instead of "please exit"), then main could be written like
def main():
while keep_going():
# your code here
This also reads pretty naturally ("while keep going do your code"). Note that in this case I'm not comparing the return value to something since True and False are truthy variables - and Python's branching control structures (like if and while) know how they work, i.e. there is no need to write keep_going() == True, and indeed it is considered un-pythonic to do so.
You can try this
def keep_going():
answer = raw_input("Do you wish to continue?")
if answer == "yes":
print "You have chosen to continue on"
else:
print "You have chosen to quit this program"
quit()

Python condition not applying (if/elif)

I have a problem with a condition in my python code.
It's a mathematics application, and here's the part of the code that is not working well:
def askNumber():
"""Asks the number to test"""
a=raw_input("Select the number to test (type 'exit' for leaving):")
if len(a)!=0 and a.lower!="exit":
try:
b= int(a)
processing(b)
except ValueError:
print "Your input is not valid. Please enter a 'number'!"
time.sleep(1)
askNumber()
elif len(a)!=0 and a.lower=="exit":
answer()
else:
print "Your input can't be 'empty'"
time.sleep(1)
askNumber()
So, when in the raw_input for "a" I type "exit", the supposed condition to apply is the elif one but ends up applying the if one, ending up printing "Your input is not valid. Please enter a 'number'!" Sorry, if it's something obvious, I'm a begginer, although I tried to find the mistake several times.
You need to call the .lower() function.
if len(a) != 0 and a.lower() != "exit":
# ...
elif len(a) != 0 and a.lower() == "exit":
There is no real need to test for len(a)!=0, simply test for a itself:
if a and a.lower() != "exit":
# ...
elif a and a.lower() == "exit":
Empty strings evaluate to False in a boolean context.
Your program flow is a bit inside out, may I suggest some improvements?
def askNumber():
"""Asks the number to test"""
while True:
a = raw_input("Select the number to test (type 'exit' for leaving):")
if not a:
print "Your input can't be 'empty'"
continue
if a.lower() == "exit":
answer()
break
try:
b = int(a)
except ValueError:
print "Your input is not valid. Please enter a 'number'!"
continue
processing(b)
Actually, the not a branch can be eliminated as well (empty inputs will be handled in except).
You could change the condition for the following one:
if a and a.lower() !="exit":
# .....
elif a and a.lower() == "exit":
answer()
elif a and not a.isdigit(): print "invalid input"
else:
#.............
Please note that yo don't need len(a) != 0 , just by using a will evaluate if it's empty or not.

Python loop restarting even though there is a try: except:

Here is the code for a small program I just wrote to test some new things I learned.
while 1:
try:
a = input("How old are you? ")
except:
print "Your answer must be a number!"
continue
years_100 = 100 - a
years_100 = str(years_100)
a = str(a)
print "You said you were "+a+", so that means you still have "+years_100+" years"
print "to go until you are 100!"
break
while 2:
try:
b = str(raw_input('Do you want to do it again? If yes enter "yes", otherwise type "no" to stop the script.'))
except:
print 'Please try again. Enter "yes" to do it again, or "no" to stop.'
continue
if b == "yes":
print 'You entered "yes". Script will now restart... '
elif b == "no":
print 'You entered "no". Script will now stop.'
break
It works fine for the for loop. If you type something other than a number, it will tell you only numbers are allowed.
However, in the 2nd loop, it asks you to enter yes or no, but if you enter in something different, it just restarts the loop instead of printing the message after
except:
What did I do wrong and how do I fix it so it displays the message I told it to?
You do not get an exception, because you are always enter a string when using raw_input(). Thus str() on the return value of raw_input() will never fail.
Instead, add an else statement to your yes or no tests:
if b == "yes":
print 'You entered "yes". Script will now restart... '
elif b == "no":
print 'You entered "no". Script will now stop.'
break
else:
print 'Please try again. Enter "yes" to do it again, or "no" to stop.'
continue
Note that you should never use a blanket except statement; catch specific exceptions. Otherwise, you'll mask unrelated problems, making it harder for you to find those problems.
Your first except handler should only catch NameError, EOFError and SyntaxError for example:
try:
a = input("How old are you? ")
except (NameError, SyntaxError, EOFError):
print "Your answer must be a number!"
continue
as that's what input() would throw.
Also note that input() takes any python expression. If I enter "Hello program" (with the quotes), no exception would be raised, but it is not a number either. Use int(raw_input()) instead, and then catch ValueError (what would be thrown if you entered anything that's not an integer) and EOFError for raw_input:
try:
a = int(raw_input("How old are you? "))
except (ValueError, EOFError):
print "Your answer must be a number!"
continue
To use the second loop to control the first, make it a function that returns True or False:
def yes_or_no():
while True:
try:
cont = raw_input('Do you want to do it again? If yes enter "yes", otherwise type "no" to stop the script.'))
except EOFError:
cont = '' # not yes and not no, so it'll loop again.
cont = cont.strip().lower() # remove whitespace and make it lowercase
if cont == 'yes':
print 'You entered "yes". Script will now restart... '
return True
if cont == 'no':
print 'You entered "no". Script will now stop.'
return False
print 'Please try again. Enter "yes" to do it again, or "no" to stop.'
and in the other loop:
while True:
# ask for a number, etc.
if not yes_or_no():
break # False was returned from yes_or_no
# True was returned, we continue the loop

How to go back to first if statement if no choices are valid

How can I have Python move to the top of an if statement if no condition is satisfied correctly.
I have a basic if/else statement like this:
print "pick a number, 1 or 2"
a = int(raw_input("> ")
if a == 1:
print "this"
if a == 2:
print "that"
else:
print "you have made an invalid choice, try again."
What I want is to prompt the user to make another choice for this if statement without them having to restart the entire program, but am very new to Python and am having trouble finding the answer online anywhere.
A fairly common way to do this is to use a while True loop that will run indefinitely, with break statements to exit the loop when the input is valid:
print "pick a number, 1 or 2"
while True:
a = int(raw_input("> ")
if a == 1:
print "this"
break
if a == 2:
print "that"
break
print "you have made an invalid choice, try again."
There is also a nice way here to restrict the number of retries, for example:
print "pick a number, 1 or 2"
for retry in range(5):
a = int(raw_input("> ")
if a == 1:
print "this"
break
if a == 2:
print "that"
break
print "you have made an invalid choice, try again."
else:
print "you keep making invalid choices, exiting."
sys.exit(1)
You can use a recursive function
def chk_number(retry)
if retry==1
print "you have made an invalid choice, try again."
a=int(raw_input("> "))
if a == 1:
return "this"
if a == 2:
return "that"
else:
return chk_number(1)
print "Pick a number, 1 or 2"
print chk_number(0)
Use a while loop.
print "pick a number, 1 or 2"
a = None
while a not in (1, 2):
a = int(raw_input("> "))
if a == 1:
print "this"
if a == 2:
print "that"
else:
print "you have made an invalid choice, try again."

How do I do something GOTO could do, in Python - reload then restart outer loop

Here is a dumbed down version of my program that I am using as an example.
I know that using GOTO is bad practice, because it leads to sloppy and confusing code, however it would be perfect for solving this problem that I have (problem detailed at bottom of post).
def prompt():
while True:
user_input = raw_input:
if input == '?':
print help_o
elif not user_input.isalpha():
print "You entered bad characters"
elif user_input == 'r': ##Restart
???????????
else:
return user_input
load_word_list() ##Load words into list
for word in wordList: ##Loop that needs to restart
for i in range(5):
to_speak = "Spell, %s" %word
subprocess.Popen(['espeak', to_speak])
answer = prompt()
if answer != word:
print "You got it wrong"
#Print results
At the Prompt, I want to reload the wordList list and restart the outer for loop.
With GOTO I could just put in place of ????... GOTO load_word_list().
But since this is Python (and Python is about good code), What is the Pythonic way to solve this problem?
You could return a tuple from prompt():
elif user_input == 'r': #Restart
return True, None
else:
return False, user_input
and
restart, answer = prompt()
if restart:
break
if answer != word:
print "You got it wrong"
Another take on jsbuenos solution. This actually does re-run the outer for loop.
def prompt():
while True:
user_input = raw_input()
if input == '?':
print help_o
elif not user_input.isalpha():
print "You entered bad characters"
elif user_input == 'r': #Restart
raise RestartException
else:
return user_input
class RestartException(Exception):
pass
while True:
load_word_list() ##Load words into list
try:
for word in wordList: ##Loop that needs to restart
for i in range(5):
to_speak = "Spell, %s" %word
subprocess.Popen(['espeak', to_speak])
answer = prompt()
if answer != word:
print "You got it wrong"
except RestartException:
# catch the exception and return to while loop
pass
else:
# exit while loop
break
class RestartException(Exception):
pass
def prompt():
while True:
user_input = raw_input:
if input == '?':
print help_o
elif not user_input.isalpha():
print "You entered bad characters"
elif user_input == 'r': #Restart
raise RestartException
else:
return user_input
load_word_list() ##Load words into list
for word in wordList: ##Loop that needs to restart
try:
for i in range(5):
to_speak = "Spell, %s" %word
subprocess.Popen(['espeak', to_speak])
answer = prompt()
if answer != word:
print "You got it wrong"
except RestartException:
pass
I don't undertand very much what you want to do, but you can remove the special case in prompt and handle the 'r' special case in the for loop directly
def prompt():
while True:
user_input = raw_input("enter words")
if input == '?':
print help_o
elif not user_input.isalpha():
print "You entered bad characters"
elif user_input == 'r': #Restart
return False
else:
return user_input
answer = True
while answer == True:
load_word_list() ##Load words into list
for word in wordList: ##Loop that needs to restart
for i in range(5):
to_speak = "Spell, %s" %word
subprocess.Popen(['espeak', to_speak])
answer = prompt()
if answer == False:
answer = True # reset for the while loop
break # break to while loop
elif answer != word:
print "You got it wrong"
print results

Categories