Is there any short way to achieve what the APT (Advanced Package Tool) command line interface does in Python?
I mean, when the package manager prompts a yes/no question followed by [Yes/no], the script accepts YES/Y/yes/y or Enter (defaults to Yes as hinted by the capital letter).
The only thing I find in the official docs is input and raw_input...
I know it's not that hard to emulate, but it's annoying to rewrite :|
As you mentioned, the easiest way is to use raw_input() (or simply input() for Python 3). There is no built-in way to do this. From Recipe 577058:
import sys
def query_yes_no(question, default="yes"):
"""Ask a yes/no question via raw_input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is True for "yes" or False for "no".
"""
valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
sys.stdout.write(question + prompt)
choice = input().lower()
if default is not None and choice == "":
return valid[default]
elif choice in valid:
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n")
(For Python 2, use raw_input instead of input.)
Usage example:
>>> query_yes_no("Is cabbage yummier than cauliflower?")
Is cabbage yummier than cauliflower? [Y/n] oops
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [Y/n] [ENTER]
>>> True
>>> query_yes_no("Is cabbage yummier than cauliflower?", None)
Is cabbage yummier than cauliflower? [y/n] [ENTER]
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [y/n] y
>>> True
I'd do it this way:
# raw_input returns the empty string for "enter"
yes = {'yes','y', 'ye', ''}
no = {'no','n'}
choice = raw_input().lower()
if choice in yes:
return True
elif choice in no:
return False
else:
sys.stdout.write("Please respond with 'yes' or 'no'")
You can use click's confirm method.
import click
if click.confirm('Do you want to continue?', default=True):
print('Do something')
This will print:
$ Do you want to continue? [Y/n]:
Should work for Python 2/3 on Linux, Mac or Windows.
Docs: http://click.pocoo.org/5/prompts/#confirmation-prompts
There is a function strtobool in Python's standard library: http://docs.python.org/2/distutils/apiref.html?highlight=distutils.util#distutils.util.strtobool
You can use it to check user's input and transform it to True or False value.
A very simple (but not very sophisticated) way of doing this for a single choice would be:
msg = 'Shall I?'
shall = input("%s (y/N) " % msg).lower() == 'y'
You could also write a simple (slightly improved) function around this:
def yn_choice(message, default='y'):
choices = 'Y/n' if default.lower() in ('y', 'yes') else 'y/N'
choice = input("%s (%s) " % (message, choices))
values = ('y', 'yes', '') if choices == 'Y/n' else ('y', 'yes')
return choice.strip().lower() in values
Note: On Python 2, use raw_input instead of input.
As mentioned by Alexander Artemenko, here's a simple solution using strtobool().
from distutils.util import strtobool
def user_yes_no_query(question):
sys.stdout.write('%s [y/n]\n' % question)
while True:
try:
return strtobool(raw_input().lower())
except ValueError:
sys.stdout.write('Please respond with \'y\' or \'n\'.\n')
Usage
>>> user_yes_no_query('Do you like cheese?')
Do you like cheese? [y/n]
Only on tuesdays
Please respond with 'y' or 'n'.
ok
Please respond with 'y' or 'n'.
y
>>> True
I know this has been answered a bunch of ways and this may not answer OP's specific question (with the list of criteria) but this is what I did for the most common use case and it's far simpler than the other responses:
answer = input('Please indicate approval: [y/n]')
if not answer or answer[0].lower() != 'y':
print('You did not indicate approval')
exit(1)
You can also use prompter.
Shamelessly taken from the README:
#pip install prompter
from prompter import yesno
>>> yesno('Really?')
Really? [Y/n]
True
>>> yesno('Really?')
Really? [Y/n] no
False
>>> yesno('Really?', default='no')
Really? [y/N]
True
I modified fmark's answer to by python 2/3 compatible more pythonic.
See ipython's utility module if you are interested in something with more error handling
# PY2/3 compatibility
from __future__ import print_function
# You could use the six package for this
try:
input_ = raw_input
except NameError:
input_ = input
def query_yes_no(question, default=True):
"""Ask a yes/no question via standard input and return the answer.
If invalid input is given, the user will be asked until
they acutally give valid input.
Args:
question(str):
A question that is presented to the user.
default(bool|None):
The default value when enter is pressed with no value.
When None, there is no default value and the query
will loop.
Returns:
A bool indicating whether user has entered yes or no.
Side Effects:
Blocks program execution until valid input(y/n) is given.
"""
yes_list = ["yes", "y"]
no_list = ["no", "n"]
default_dict = { # default => prompt default string
None: "[y/n]",
True: "[Y/n]",
False: "[y/N]",
}
default_str = default_dict[default]
prompt_str = "%s %s " % (question, default_str)
while True:
choice = input_(prompt_str).lower()
if not choice and default is not None:
return default
if choice in yes_list:
return True
if choice in no_list:
return False
notification_str = "Please respond with 'y' or 'n'"
print(notification_str)
For Python 3, I'm using this function:
def user_prompt(question: str) -> bool:
""" Prompt the yes/no-*question* to the user. """
from distutils.util import strtobool
while True:
user_input = input(question + " [y/n]: ")
try:
return bool(strtobool(user_input))
except ValueError:
print("Please use y/n or yes/no.\n")
The strtobool() function converts a string into a bool. If the string cant be parsed it will raise a ValueError.
In Python 3 raw_input() has been renamed to input().
As Geoff said, strtobool actually returns 0 or 1, therefore the result has to be cast to bool.
This is the implementation of strtobool, if you want special words to be recognized as true, you can copy the code and add your own cases.
def strtobool (val):
"""Convert a string representation of truth to true (1) or false (0).
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
'val' is anything else.
"""
val = val.lower()
if val in ('y', 'yes', 't', 'true', 'on', '1'):
return 1
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
return 0
else:
raise ValueError("invalid truth value %r" % (val,))
on 2.7, is this too non-pythonic?
if raw_input('your prompt').lower()[0]=='y':
your code here
else:
alternate code here
it captures any variation of Yes at least.
Doing the same with python 3.x, where raw_input() doesn't exist:
def ask(question, default = None):
hasDefault = default is not None
prompt = (question
+ " [" + ["y", "Y"][hasDefault and default] + "/"
+ ["n", "N"][hasDefault and not default] + "] ")
while True:
sys.stdout.write(prompt)
choice = input().strip().lower()
if choice == '':
if default is not None:
return default
else:
if "yes".startswith(choice):
return True
if "no".startswith(choice):
return False
sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n")
You could try something like the code below to be able to work with choices from the variable 'accepted' show here:
print( 'accepted: {}'.format(accepted) )
# accepted: {'yes': ['', 'Yes', 'yes', 'YES', 'y', 'Y'], 'no': ['No', 'no', 'NO', 'n', 'N']}
Here is the code ..
#!/usr/bin/python3
def makeChoi(yeh, neh):
accept = {}
# for w in words:
accept['yes'] = [ '', yeh, yeh.lower(), yeh.upper(), yeh.lower()[0], yeh.upper()[0] ]
accept['no'] = [ neh, neh.lower(), neh.upper(), neh.lower()[0], neh.upper()[0] ]
return accept
accepted = makeChoi('Yes', 'No')
def doYeh():
print('Yeh! Let\'s do it.')
def doNeh():
print('Neh! Let\'s not do it.')
choi = None
while not choi:
choi = input( 'Please choose: Y/n? ' )
if choi in accepted['yes']:
choi = True
doYeh()
elif choi in accepted['no']:
choi = True
doNeh()
else:
print('Your choice was "{}". Please use an accepted input value ..'.format(choi))
print( accepted )
choi = None
As a programming noob, I found a bunch of the above answers overly complex, especially if the goal is to have a simple function that you can pass various yes/no questions to, forcing the user to select yes or no. After scouring this page and several others, and borrowing all of the various good ideas, I ended up with the following:
def yes_no(question_to_be_answered):
while True:
choice = input(question_to_be_answered).lower()
if choice[:1] == 'y':
return True
elif choice[:1] == 'n':
return False
else:
print("Please respond with 'Yes' or 'No'\n")
#See it in Practice below
musical_taste = yes_no('Do you like Pine Coladas?')
if musical_taste == True:
print('and getting caught in the rain')
elif musical_taste == False:
print('You clearly have no taste in music')
This is what I use:
import sys
# cs = case sensitive
# ys = whatever you want to be "yes" - string or tuple of strings
# prompt('promptString') == 1: # only y
# prompt('promptString',cs = 0) == 1: # y or Y
# prompt('promptString','Yes') == 1: # only Yes
# prompt('promptString',('y','yes')) == 1: # only y or yes
# prompt('promptString',('Y','Yes')) == 1: # only Y or Yes
# prompt('promptString',('y','yes'),0) == 1: # Yes, YES, yes, y, Y etc.
def prompt(ps,ys='y',cs=1):
sys.stdout.write(ps)
ii = raw_input()
if cs == 0:
ii = ii.lower()
if type(ys) == tuple:
for accept in ys:
if cs == 0:
accept = accept.lower()
if ii == accept:
return True
else:
if ii == ys:
return True
return False
def question(question, answers):
acceptable = False
while not acceptable:
print(question + "specify '%s' or '%s'") % answers
answer = raw_input()
if answer.lower() == answers[0].lower() or answers[0].lower():
print('Answer == %s') % answer
acceptable = True
return answer
raining = question("Is it raining today?", ("Y", "N"))
This is how I'd do it.
Output
Is it raining today? Specify 'Y' or 'N'
> Y
answer = 'Y'
Here's my take on it, I simply wanted to abort if the user did not affirm the action.
import distutils
if unsafe_case:
print('Proceed with potentially unsafe thing? [y/n]')
while True:
try:
verify = distutils.util.strtobool(raw_input())
if not verify:
raise SystemExit # Abort on user reject
break
except ValueError as err:
print('Please enter \'yes\' or \'no\'')
# Try again
print('Continuing ...')
do_unsafe_thing()
How about this:
def yes(prompt = 'Please enter Yes/No: '):
while True:
try:
i = raw_input(prompt)
except KeyboardInterrupt:
return False
if i.lower() in ('yes','y'): return True
elif i.lower() in ('no','n'): return False
Since the answer is expected yes or no, in the examples below, the first solution is to repeat the question using the function while, and the second solution is to use recursion - is the process of defining something in terms of itself.
def yes_or_no(question):
while "the answer is invalid":
reply = str(input(question+' (y/n): ')).lower().strip()
if reply[:1] == 'y':
return True
if reply[:1] == 'n':
return False
yes_or_no("Do you know who Novak Djokovic is?")
second solution:
def yes_or_no(question):
"""Simple Yes/No Function."""
prompt = f'{question} ? (y/n): '
answer = input(prompt).strip().lower()
if answer not in ['y', 'n']:
print(f'{answer} is invalid, please try again...')
return yes_or_no(question)
if answer == 'y':
return True
return False
def main():
"""Run main function."""
answer = yes_or_no("Do you know who Novak Djokovic is?")
print(f'you answer was: {answer}')
if __name__ == '__main__':
main()
One-liner with Python 3.8 and above:
while res:= input("When correct, press enter to continue...").lower() not in {'y','yes','Y','YES',''}: pass
Python x.x
res = True
while res:
res = input("Please confirm with y/yes...").lower(); res = res not in {'y','yes','Y','YES',''}
What I used to do is...
question = 'Will the apple fall?'
print(question)
answer = int(input("Pls enter the answer: "
if answer == "y",
print('Well done')
print(answer)
Related
I created a one-rep max calculator for powerlifting. Everything runs fine but I want it to end with a restart prompt in case the user wanted to calculate another lift. (Keep in mind I am very new to coding and Python).
I have played around with different variables but I am struggling with properly declaring the function and then running the loop.
Welcome= 'Hello and welcome to one rep max calculator, Please follow the prompt below'
print (Welcome)
reps= int(input('Rep Count?'))
initial_weight= int(input('Weight lifted?'))
bench_max=(.0333 * reps + 1) * initial_weight
print (bench_max)
reply= 'y'
question= 'Do you want another calculation?'
def yes_or_no(reply):
reply= 'y'
while "the answer is invalid":
reply = str(input(question+' (y/n): ')).lower().strip()
if reply[0] == 'y':
return True
if reply[0] == 'n':
return False
yes_or_no(reply)
There is no error message, but the program doesn't restart, regardless of whether I hit yes or no.
This will make the prompt ask until you get a valid answer.
def yes_or_no():
reply = ''
while reply not in ['y', 'n']:
reply = input(question+' (y/n): ').lower().strip()
if reply == 'y':
return True
if reply == 'n':
return False
If you want the program to exit when you say no, you can do the following:
import sys
sys.exit() # replace the 'return False' above with this statement
Then to get it to run continuously until you tell it to exit, just put the code you want to repeat in a while loop.
Once you fix the issue Johnny Mopp pointed out, you can do
def yes_or_no(reply):
reply= 'y'
while "the answer is invalid":
reply = str(input(question+' (y/n): ')).lower().strip()
if reply[0] == 'y':
return True
if reply[0] == 'n':
return False
while True:
Welcome= 'Hello and welcome to one rep max calculator, Please follow the prompt below'
print (Welcome)
reps= int(input('Rep Count?'))
initial_weight= int(input('Weight lifted?'))
bench_max=(.0333 * reps + 1) * initial_weight
print (bench_max)
reply= 'y'
question= 'Do you want another calculation?'
if (not yes_or_no(reply)):
break
print("what type of device do you have phone, tablet or laptop(put brackets at the end of your answer)?")
answer = input ("press enter and type in your answer. phone(), tablet() or console()")
def phone():
import webbrowser
print("Do you have an iphone or samsung?")
answer = input ('iphone/samsung:')
if answer == "iphone":
print("what type of iphone?")
answer = input ('5, 6 or 7:')
if answer == "samsung":
print("what type of samsung do you have?")
answer = input ('s5, s6 or s7:')
Indent block, be more careful!
def phone():
import webbrowser
print("Do you have an iphone or samsung?")
answer = input ('iphone/samsung:')
if answer == "iphone":
print("what type of iphone?")
answer = input ('5, 6 or 7:')
if answer == "samsung":
print("what type of samsung do you have?")
answer = input ('s5, s6 or s7:')
x = input("press enter and type in your answer. phone(), tablet() or console() ")
if x == 'phone()':
phone()
elif x == 'tablet()':
tablet()
elif x == 'console()':
console()
Essentially, what you have is this...
def foo():
print("stuff")
answer = input("type foo()")
And answer == "foo()" is True.
You never called foo(), though, you just typed it in as a string.
You need to run it.
exec(answer)
But, exec is really bad, so instead, you should instead use if and elif's to call the corresponding function.
if answer == 'foo()':
foo()
I have been trying to program a maths quiz that both works and is as efficient as possible. Looking over my code I saw I had a lot of integer inputs and that lead to me having the program to ask the question/exit the system if the criteria isn't met, so to help me I thought that it would be useful to create a new function. Here is my attempt:
def prompt_int(prompt=''):
while True:
if status == prompt_int(prompt=''):
val = input(prompt)
if val in (1,2):
return int(val)
return true
elif status != prompt_int(prompt=''):
val = input(prompt)
if val in (1,2,3):
return int(val)
return true
else:
print("Not a valid number, please try again")
However, when I try to implement this function around my code it doesn't work properly as it says that status isn't defined however, when I do define status it goes into a recursion loop. How can I fix this problem?
Here is my original code before i try to implement this function:
import sys
import random
def get_bool_input(prompt=''):
while True:
val = input(prompt).lower()
if val == 'yes':
return True
elif val == 'no':
return False
else:
sys.exit("Not a valid input (yes/no is expected) please try again")
status = input("Are you a teacher or student? Press 1 if you are a student or 2 if you are a teacher")# Im tring to apply the new function here and other places that require integer inputs
if status == "1":
score=0
name=input("What is your name?")
print ("Alright",name,"welcome to your maths quiz."
"Remember to round all answer to 5 decimal places.")
level_of_difficulty = int(input(("What level of difficulty are you working at?\n"
"Press 1 for low, 2 for intermediate "
"or 3 for high\n")))
if level_of_difficulty not in (1,2,3):
sys.exit("That is not a valid level of difficulty, please try again")
if level_of_difficulty == 3:
ops = ['+', '-', '*', '/']
else:
ops = ['+', '-', '*']
for question_num in range(1, 11):
if level_of_difficulty == 1:
number_1 = random.randrange(1, 10)
number_2 = random.randrange(1, 10)
else:
number_1 = random.randrange(1, 20)
number_2 = random.randrange(1, 20)
operation = random.choice(ops)
maths = round(eval(str(number_1) + operation + str(number_2)),5)
print('\nQuestion number: {}'.format(question_num))
print ("The question is",number_1,operation,number_2)
answer = float(input("What is your answer: "))
if answer == maths:
print("Correct")
score = score + 1
else:
print ("Incorrect. The actual answer is",maths)
if score >5:
print("Well done you scored",score,"out of 10")
else:
print("Unfortunately you only scored",score,"out of 10. Better luck next time")
class_number = input("Before your score is saved ,are you in class 1, 2 or 3? Press the matching number")
while class_number not in ("1","2","3"):
print("That is not a valid class, unfortunately your score cannot be saved, please try again")
class_number = input("Before your score is saved ,are you in class 1, 2 or 3? Press the matching number")
else:
filename = (class_number + "txt")
with open(filename, 'a') as f:
f.write("\n" + str(name) + " scored " + str(score) + " on difficulty level " + str(level_of_difficulty))
with open(filename, 'a') as f:
f = open(filename, "r")
lines = [line for line in f if line.strip()]
f.close()
lines.sort()
if get_bool_input("Do you wish to view previous results for your class"):
for line in lines:
print (line)
else:
sys.exit("Thanks for taking part in the quiz, your teacher should discuss your score with you later")
if status == "2":
class_number = input("Which classes scores would you like to see? Press 1 for class 1, 2 for class 2 or 3 for class 3")
if class_number not in (1,2,3):
sys.exit("That is not a valid class")
filename = (class_number + "txt")
with open(filename, 'a') as f:
f = open(filename, "r")
lines = [line for line in f if line.strip()]
f.close()
lines.sort()
for line in lines:
print (line)
Well, just a part:
def prompt_int(prompt=""):
while True:
val = input(prompt)
if val in ("1", "2"):
return int(val), True
Will ask again and again. And return when the user enter "1" or "2"!
But better: "if val in "12":
def prompt_int(prompt=""):
while True:
val = input(prompt)
if val.isdigit():
return int(val)
Hi if you dont want to have valid values send to your you could change your code as the function above.
But you could also change it to do the system exits:
def prompt_int(prompt="", authorized=()):
while True:
val = raw_input(prompt)
if val.isdigit():
if int(val) in authorized:
return int(val)
else:
sys.exit("Bla bla bla too bad")
def prompt_int(prompt=''):
while True:
if status == prompt_int(prompt=''):
This line will look for the name "status" in the global namespace (module's namespace), and raise a NameError if there's no global variable named 'status'.
If there's one, it will then recursively calls prompt_int without any possible termination, resulting theoretically in an endless recursion, but practically (in CPython at least) in a RuntimeError when it will hit the maximum recursion depth.
There are also quite a few other things that won't work as you expect:
val = input(prompt)
if val in (1,2):
In Python 3.x, val will be a string, so it will never compare equal to an int. In Python 2.x, input() is a shortcut for eval(raw_input()), which might return an int, but is also a huge security flaw since it unconditionnally execute untrusted code.
return int(val)
return true
The second return statement will never be executed, obviously, since the function will exit at the first one.
A simpler implementation might look like this:
# rebinds raw_input to input for python < 3
import sys
if sys.version_info.major < 3:
input = raw_input
def prompt_int(prompt='', choices=None):
while True:
val = input(prompt)
try:
val = int(val)
if choices and val not in choices:
raise ValueError("{} is not in {}".format(val, choices))
return val
except (TypeError, ValueError) as e:
print(
"Not a valid number ({}), please try again".format(e)
)
While we're at it, there's room for improvement in other parts of your code. Let's start with this:
def get_bool_input(prompt=''):
while True:
val = input(prompt).lower()
if val == 'yes':
return True
elif val == 'no':
return False
else:
sys.exit("Not a valid input (yes/no is expected) please try again")
First point: your naming is not consistent. If your other function is named prompt_int, this one should be named prompt_bool. Also, you have one function (prompt_int) looping forever and the other one exiting the whole program on invalid input, which is another inconsistency. If you want to allow the user to exit on any prompt, provide an explicit option for it, ie:
def prompt_bool(prompt, quit='Q'):
prompt += " (hit '{}' to exit) : ".format(quit)
while True:
val = input(prompt).strip().upper()
if val == quit:
sys.exit("Goodbye")
elif val == 'yes':
return True
elif val == 'no':
return False
else:
print "Invalid input '{}', please try again".format(val)
Of course you then want to provide the same option in prompt_int(), which leads to a more generic function:
def get_input_or_quit(prompt, quit="Q"):
prompt += " (hit '{}' to exit) : ".format(quit)
val = input(prompt).strip()
if val.upper() == quit:
sys.exit("Goodbye")
return val
def prompt_bool(prompt):
while True:
val = get_input_or_quit(prompt).lower()
if val == 'yes':
return True
elif val == 'no':
return False
else:
print "Invalid input '{}', please try again".format(val)
And of course you also replace the call to input by a call to get_input_or_quit in prompt_int.
We could go on for long - splitting all your code in distinct, self-contained function, writing a "main()" function to drive them (instead of having the "main" part at the top level), and obviously using the operator module instead of eval().
Below is my complete code with comments describing what each section should operate. In the picture,I have provided it shows how each condition would be verified with depending on the users inputting 'y' for yes and 'n' for no concerning symptoms.
The problem, I'm having is that I should be only asking the minimal question, in order to get the diagnosis of the exact condition without having to answer any other questions.
Ex. Don't have a fever and don't have a stuffy nose: Hypochondriac.
It should print: You are Hypochondriac, just by inputting no for Fever and no for a Stuffy Nose.
I have to go through the entire questionnaire to display the diagnosis but that shouldn't be.
How can i modify my code to only ask the minimal questions required?
![#Description: Creata a medical diagnosis program
#that asks the user whether they have a fever, a rash,
#a stuffy nose and if their ear hurts.
#Get user inputs on whether they have specific conditions
userFever = input("Do you have a fever (y/n): ")
userRash = input("Do you have a rash (y/n): ")
userEar = input("Does your ear hurt (y/n): ")
userNose = input("Do you have a stuffy nose (y/n): ")
#Conditional statements that determine the diagnosis of the user
if userFever == 'n' and userNose == 'n':
print("Diagnosis: You are Hypchondriac")
elif userFever == 'n' and userNose == 'y':
print("Diagnosis: You have a Head Cold")
elif userFever == 'y' and userRash == 'n' and userEar == 'y':
print("Diagnosis: You have an ear infection")
elif userFever == 'y' and userRash == 'n' and userEar == 'n':
print("Diagnosis: You have the flu")
elif userFever == 'y' and userRash == 'y':
print("Diagnosis: You have the measles")][1]
Just construct a hierarchy of questions depending on which one discriminates most. In your case is very easy because the symptoms are totally disjoint. The fever would be the top question: if you don't have fever, you're only interested in knowing if there's stuffy nose or no. If there is, you want to know if there's a rash before asking for the ear. So, I'd start like this:
userFever = input("Do you have a fever (y/n): ")
if userFever == 'n':
userNose = input("Do you have a stuffy nose (y/n): ")
if userNose == 'n':
...
else:
...
else:
# The other questions
Given that this looks like homework, I leave the rest to you :P
Well especially if you want to extend this program I would recommend using something like this:
from itertools import islice
class Diagnosis:
diagnoses = ("You are Hypchondriac", "You have a Head Cold",
"You have an ear infection", "You have the flu", "You have the measles"
)
def __init__(self):
self.diagnosis = 0 # Consider using an enum for this
self.queue = (self.check_fever, self.check_nose, self.check_rash,
self.check_ear)
def ask(self, question):
answer = input(question + " [y/N] ").lower()
return answer != "" and answer[0] == "y"
def make(self):
queue_iter = iter(self.queue)
for func in queue_iter:
skip = func()
# return -1 if you want to break the queue
if skip == -1:
break
if skip > 0:
next(islice(queue_iter, skip, skip + 1))
def check_fever(self):
return 1 if self.ask("Do you have a fever?") else 0
def check_nose(self):
if self.ask("Do you have a stuffy nose?"):
self.diagnosis = 1
return -1
def check_rash(self):
if self.ask("Do you have a rash?"):
self.diagnosis = 4
return -1
return 0
def check_ear(self):
if self.ask("Does your ear hurt?"):
self.diagnosis = 2
else:
self.diagnosis = 3
return -1
def get_result(self):
return self.diagnoses[self.diagnosis]
if __name__ == "__main__":
diagnosis = Diagnosis()
diagnosis.make()
print("Diagnosis: " + diagnosis.get_result())
Basically put all functions you need in the queue and return the number of functions you want to skip or return -1 if you're finished.
This is the old 'Guess who' game - otherwise known as a binary decision tree.
Rather than do your homework here is a different example
male?
/ \
N Y
blonde? beard?
/ \ / \
N Y N Y
Sam Jane hat? Andy
/ \
N Y
Bob Fred
In terms of solving these then an OO approach is almost always best as it is easily understandable and adding extra items easy. Use a recursive method to get the answer...
class Question(object):
no = None
yes = None
def __init__(self, question):
self.question = question
def answer(self):
r = raw_input("%s (y/N): " % self.question).lower()
next = self.yes if r == 'y' else self.no
# check if we need to descend to the next question
if hasattr(next, 'answer'):
return next.answer()
# otherwise just return the answer
return next
# create a bunch of questions
male = Question("Are you male?")
blonde = Question("Are you blonde?")
beard = Question("Do you have a beard?")
hat = Question("Are you wearing a hat?")
# hook up all the questions according to your diagram
male.no = blonde
male.yes = beard
blonde.no = "Sam"
blonde.yes = "Jane"
beard.no = hat
beard.yes = "Andy"
hat.no = "Bob"
hat.yes = "Fred"
# start the whole thing rolling
print "You are %s." % male.answer()
I'm very very new to programming and for a school project (50% of my final grade) I had to create a Python program that did roughly this.
I've had some help from my older brother and my teacher but mainly did it myself with some flow charts etc, so please forgive me if I haven't followed conventional rules and things of this nature, or if my code is messy. I will finalise it, just needed bait of help/support from the pro's.
This is my code and I have an issue with it. Once I have pressed 'y' and then 'y' again on the displayMenu() why doesn't it run oldUser()
Also, if any of you have any suggestion on what could make my code better, or I could improve it would be very helpful and I will take it on board.
import os # allows me to use functions defined elsewhere. os module allows for multi platforming.
import sys
words = []
users = {}
status = ""
def teacher_enter_words():
done = False
print 'Hello, please can you enter a word and definition pair.'
while not done:
word = raw_input('\nEnter a word: ')
deff = raw_input('Enter the definition: ')
# append a tuple to the list so it can't be edited.
words.append((word, deff))
add_word = raw_input('Add another word? (y/n): ')
if add_word.lower() == 'n':
done = True
def student_take_test():
student_score = 0
for pair in words:
print 'Definition:', pair[1]
inp = raw_input('Enter word: ')
student_score += check_error(pair[0], inp)
print 'Correct spelling:', pair[0], '\n'
print 'Your score:', student_score
def check_error(correct, inputt):
len_c = len(correct)
len_i = len(inputt)
# threshold is how many incorrect letters do we allow before a
# minor error becomes a major error.
# 1 - allow 1 incorrect letter for a minor error ( >= 2 becomes major error)
threshold = 1
# immediately check if the words are the same length
num_letters_incorrect = abs(len_c - len_i) # abs() method returns value of x - positive dist between x and zero
if num_letters_incorrect == 0:
for i in xrange(0, len(correct)):
if correct[i] != inputt[i]:
num_letters_incorrect += 1
if num_letters_incorrect <= threshold:
if num_letters_incorrect == 0:
return 2 # no incorrect letter.
else:
return 1 # minor error.
else:
return 0 # major error.
def displayMenu():
status = raw_input('Are you a registered user? y/n?: ')
if status == raw_input == 'y':
oldUser()
elif status == 'n':
newUser()
def newUser():
createLogin = raw_input('Create login name: ')
if createLogin in users:
print '\nLogin name already exist!\n'
else:
createPassw = raw_input('Create password: ')
users[createLogin] = createPassw
print '\nUser created!\n'
def oldUser():
login = raw_input('Enter login name: ')
passw = raw_input('Enter password: ')
if login in users and users[login] == passw:
print '\nLogin successful!\n'
else:
print "\nUser doesn't exist or wrong password!\n"
if __name__ == '__main__':
running = True
while running:
os.system('cls' if os.name == 'nt' else 'clear') # multi-platform, executing a shell command
reg = raw_input('Do you want to start the program? y/n?').lower()
if reg == 'y' or reg == 'yes':
displayMenu()
else: sys.exit(0)
inp = raw_input('Are you a Teacher or a Student? (t/s): ').lower()
if inp == 't' or inp == 'teacher':
teacher_enter_words()
else:
student_take_test()
running = False
raw_input is a function. status == raw_input == 'y' will never be true: that is comparing status with the function, and with 'y'.
I suspect that's simply a typo, and you just meant if status == 'y':