Python中请求用户输入,直到给出有效的输入

问题:

我正在编写一个必须接受用户输入的程序。

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

如果用户输入合理的数据,这可以预期。
class=”lang-none prettyprint-override”>

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

但是如果他们犯了一个错误,那就崩溃了:
class=”lang-none prettyprint-override”>

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

而不是崩溃,我想要尝试再次获得输入。喜欢这个:
class=”lang-none prettyprint-override”>

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

我该如何做到这一点?如果我也想拒绝像-1这样的值,这是有效的int,但在这种情况下是荒谬的呢?

回答:

完成此操作的最简单的方法是将input方法放在while循环中。当您输入错误时使用continue,当您满意时,使用break退出循环。

当您的输入可能会提高异常时

使用try and catch来检测用户何时输入无法解析的数据。

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

实施自己的验证规则

如果要拒绝Python可以成功解析的值,可以添加自己的验证逻辑。

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

组合异常处理和自定义验证

上述两种技术都可以组合成一个循环。

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0: print("Sorry, your response must not be negative.") continue else: #age was successfully parsed, and we're happy with its value. #we're ready to exit the loop. break if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

将其全部封装在一个函数中

如果您需要向用户询问很多不同的值,那么将这段代码放在一个函数中可能是有用的,因此您不必每次都重新输入。

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

把它们放在一起

你可以扩展这个想法,使一个非常通用的输入函数:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_: raise ValueError("min_ must be less than or equal to max_.") while True: ui = input(prompt) if type_ is not None: try: ui = type_(ui) except ValueError: print("Input type must be {0}.".format(type_.__name__)) continue if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {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

使用如:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer", str.lower, range_=('a', 'b', 'c', 'd'))

常见的陷阱,为什么要避免他们

冗余使用冗余

这种方法有效,但通常被认为是差的风格:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

最初可能看起来很有吸引力,因为它比while True方法更短,但是它违反了软件开发的Don’t Repeat Yourself原则。这增加了系统中错误的可能性。如果您想通过将input更改为raw_input来反向输入2.7,但是意外仅更改上述第一个input?这是一个SyntaxError等待发生。

递归让你堆栈溢出

如果您刚刚了解了递归,您可能会尝试在get_non_negative_int中使用它,以便可以处理while循环。

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

这似乎大部分时间都可以正常工作,但是如果用户足够多地输入无效数据,脚本将以RuntimeError: maximum recursion depth exceeded结束。你可能认为“没有傻瓜会连续1000个错误”,但你低估了愚人的聪明才智!

翻译整理: codewenda.com
英文原文:Asking the user for input until they give a valid response

发表评论

电子邮件地址不会被公开。 必填项已用*标注

+ 4 = 7