python - Asking the user for input until they give a valid response -
i writing program must accept input user.
#note: python 2.7 users should use `raw_input`, equivalent of 3.x's `input` age = int(input("please enter age: ")) if age >= 18: print("you able vote in united states!") else: print("you not able vote in united states.")
this works expected if user enters sensible data.
c:\python\projects> canyouvote.py please enter age: 23 able vote in united states!
but if make mistake, crashes:
c:\python\projects> canyouvote.py please enter age: dickety 6 traceback (most recent call last): file "canyouvote.py", line 1, in <module> age = int(input("please enter age: ")) valueerror: invalid literal int() base 10: 'dickety six'
instead of crashing, try getting input again. this:
c:\python\projects> canyouvote.py please enter age: dickety 6 sorry, didn't understand that. please enter age: 26 able vote in united states!
how can accomplish this? if wanted reject values -1
, valid int
, nonsensical in context?
the simplest way accomplish put input
method in while loop. use continue
when bad input, , break
out of loop when you're satisfied.
when input might raise exception
use try , catch detect when user enters data can't parsed.
while true: try: # note: python 2.x users should use raw_input, equivalent of 3.x's input age = int(input("please enter age: ")) except valueerror: print("sorry, didn't understand that.") #better try again... return start of loop continue else: #age parsed! #we're ready exit loop. break if age >= 18: print("you able vote in united states!") else: print("you not able vote in united states.")
implementing own validation rules
if want reject values python can parse, can add own validation logic.
while true: data = input("please enter loud message (must caps): ") if not data.isupper(): print("sorry, response not loud enough.") continue else: #we're happy value given. #we're ready exit loop. break while true: data = input("pick answer d:") if data.lower() not in ('a', 'b', 'c', 'd'): print("not appropriate choice.") else: break
combining exception handling , custom validation
both of above techniques can combined 1 loop.
while true: try: age = int(input("please enter age: ")) except valueerror: print("sorry, didn't understand that.") continue if age < 0: print("sorry, response must not negative.") continue else: #age parsed, , we're happy value. #we're ready exit loop. break if age >= 18: print("you able vote in united states!") else: print("you not able vote in united states.")
encapsulating in function
if need ask user lot of different values, might useful put code in function, don't have retype every time.
def get_non_negative_int(prompt): while true: try: value = int(input(prompt)) except valueerror: print("sorry, didn't understand that.") continue if value < 0: print("sorry, response must not negative.") continue else: break return value age = get_non_negative_int("please enter age: ") kids = get_non_negative_int("please enter number of children have: ") salary = get_non_negative_int("please enter yearly earnings, in dollars: ")
putting together
you can extend idea make generic input function:
def sanitised_input(prompt, type_=none, min_=none, max_=none, range_=none): if min_ not none , max_ not none , max_ < min_: raise valueerror("min_ must less or equal max_.") while true: ui = input(prompt) if type_ not none: try: ui = type_(ui) except valueerror: print("input type must {0}.".format(type_.__name__)) continue if max_ not none , ui > max_: print("input must less or equal {0}.".format(max_)) elif min_ not none , ui < min_: print("input must greater or equal {0}.".format(min_)) elif range_ not none , ui not in range_: if isinstance(range_, range): template = "input must between {0.start} , {0.stop}." print(template.format(range_)) else: template = "input must {0}." if len(range_) == 1: print(template.format(*range_)) else: print(template.format(" or ".join((", ".join(map(str, range_[:-1])), str(range_[-1]))))) else: return ui
with usage such as:
age = sanitised_input("enter age: ", int, 1, 101) answer = sanitised_input("enter answer", str.lower, range_=('a', 'b', 'c', 'd'))
common pitfalls, , why should avoid them
the redundant use of redundant input
statements
this method works considered poor style:
data = input("please enter loud message (must caps): ") while not data.isupper(): print("sorry, response not loud enough.") data = input("please enter loud message (must caps): ")
it might attractive because it's shorter while true
method, violates don't repeat yourself principle of software development. increases likelihood of bugs in system. if want backport 2.7 changing input
raw_input
, accidentally change first input
above? it's syntaxerror
waiting happen.
recursion blow stack
if you've learned recursion, might tempted use in get_non_negative_int
can dispose of while loop.
def get_non_negative_int(prompt): try: value = int(input(prompt)) except valueerror: print("sorry, didn't understand that.") return get_non_negative_int(prompt) if value < 0: print("sorry, response must not negative.") return get_non_negative_int(prompt) else: return value
this appears work fine of time, if user enters invalid data enough times, script terminate runtimeerror: maximum recursion depth exceeded
. may think "no fool make 1000 mistakes in row", you're underestimating ingenuity of fools!
Comments
Post a Comment