要求用户输入,直到他们给出有效响应

新手上路,请多包涵

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

 #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.")

只要用户输入有意义的数据,该程序就会按预期运行。

 Please enter your age: 23
You are able to vote in the United States!

但如果用户输入无效数据,它将失败:

 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'

我希望程序不再崩溃,而是再次请求输入。像这样:

 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 )?

原文由 Kevin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 263
2 个回答

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

当您的输入可能引发异常时

使用 tryexcept 检测用户何时输入无法解析的数据。

 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:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        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'))

常见的陷阱,以及为什么要避免它们

冗余语句的冗余使用 input 语句

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

 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 方法更短,但它违反了软件开发的 “不要重复自己” 原则。这会增加系统中出现错误的可能性。如果您想通过将 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 次错误”,但你低估了傻子的聪明才智!

原文由 Kevin 发布,翻译遵循 CC BY-SA 4.0 许可协议

你为什么要执行 while True 然后跳出这个循环,同时你也可以将你的要求放在 while 语句中,因为你想要的只是一旦你有年龄就停止?

 age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
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.")

这将导致以下结果:

 Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

这将起作用,因为年龄永远不会有没有意义的价值,并且代码遵循您的“业务流程”的逻辑

原文由 Steven Stip 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题