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

Python 请求用户输入,直到他们给出有效响应,python,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 t

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

#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.")
只要用户输入有意义的数据,程序就会按预期工作

C:\Python\Projects>canyouvote.py 请输入您的年龄:23岁 你可以在美国投票! 但如果用户输入无效数据,则会失败:

C:\Python\Projects>canyouvote.py
请输入您的年龄:dickety六岁 回溯最近一次呼叫上次: 文件canyouvote.py,第1行,在 年龄=首次输入请输入您的年龄: ValueError:基数为10的int的文本无效:“dickety六” 我希望程序再次请求输入,而不是崩溃。像这样:

C:\Python\Projects>canyouvote.py
请输入您的年龄:dickety六岁 对不起,我不明白。 请输入您的年龄:26岁 你可以在美国投票! 当输入非感官数据时,如何使程序请求有效输入而不是崩溃


我如何拒绝像-1这样的值,它是一个有效的int,但在这种情况下毫无意义?

实现这一点的最简单方法是将输入方法放入while循环中。当你得到错误的输入时使用,当你满意时打破循环

当您的输入可能引发异常时 用于检测用户何时输入无法解析的数据

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.")
常见的陷阱,以及您应该避免它们的原因 冗余输入语句的冗余使用 这种方法可行,但通常被认为是拙劣的风格:

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方法短,但它违反了软件开发的原则。这会增加系统中出现错误的可能性。如果您想通过将输入更改为raw_输入,而意外地仅更改上面的第一个输入,从而将后端口转换为2.7,该怎么办?这是一个即将发生的语法错误

递归会毁掉你的堆栈 如果您刚刚了解了递归,您可能会尝试在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

这似乎在大多数情况下都可以正常工作,但如果用户输入无效数据的次数足够多,脚本将以运行时错误终止:超过最大递归深度。你可能认为没有傻瓜会连续犯1000个错误,但你低估了傻瓜的聪明才智

尽管公认的答案令人惊讶。我还想分享一下这个问题的快速解决方法。这也解决了消极的年龄问题

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))
另外,这段代码是针对Python3.x编写的。

为什么要执行一段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.

这将起作用,因为年龄永远不会有一个没有意义的值,代码遵循您的业务流程的逻辑。因此,我最近正在处理类似的问题,我提出了以下解决方案,它使用一种在以任何逻辑方式检查输入之前拒绝垃圾的方法

阅读\u单键\u按键礼貌

您可以找到完整的模块

例如:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _
请注意,此实现的本质是,一旦读取非数字的内容,它就会关闭stdin。a后我没有按enter键,但我需要按数字

您可以将它和同一模块中的thismany函数合并,以便只允许(比如)三位数字。

虽然try/except块可以工作,但完成此任务的更快更干净的方法是使用str.isdigit


您可以编写更通用的逻辑,允许用户只输入特定的次数,因为在许多实际应用程序中都会出现相同的用例

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.
试试这个:-

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

使用while语句,直到用户输入一个真值,如果输入值不是一个数字或是一个空值,则跳过它并尝试再次询问,以此类推。 在这个例子中,我试图真实地回答你的问题。如果我们假设我们的年龄在1到150之间,那么输入值被接受,否则它是一个错误的值。 对于终止程序,用户可以使用0键并将其作为值输入

注意:阅读代码顶部的注释


您可以将input语句设置为while True循环,以便它重复请求用户输入,然后在用户输入您想要的响应时中断该循环。您可以使用try和except块来处理无效响应

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

var变量的作用是,如果用户输入的是字符串而不是整数,程序将不会返回,您将无法在美国投票。

使用自定义ValidationError和可选范围进行输入验证的另一种解决方案 整数输入的验证:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))
用法:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)
输出:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

基于Daniel Q和Patrick Artner的优秀建议, 这里有一个更普遍的解决方案

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)
我选择了显式if和raise语句,而不是断言, 因为断言检查可能被关闭, 而验证应始终处于开启状态,以提供健壮性

这可用于获取不同类型的输入, 具有不同的验证条件。 例如:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})
或者,回答原来的问题:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
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.")

好问题!您可以为此尝试以下代码=

此代码用于查找输入年龄的数据类型。然后遵循以下算法:

请用户输入她/他的年龄

1.1。如果年龄是float或int数据类型:

检查年龄是否大于等于18岁。如果年龄>=18,打印适当的输出并退出


使用递归函数检查是否0持久用户输入:

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
一串 整数 最后,问题要求:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)
或者看,妈妈,不要打圈 从itertools导入链,重复 prompts=chain[输入数字:],不是数字!再试一次: 回复=mapinput,提示 valid_response=nextfilterstr.isdigit,回复 打印有效的\u响应 输入一个数字:a 不是数字!再试一次:b 不是数字!再试一次:1 1. 或者,如果您希望将错误的输入消息与其他答案中的输入提示分隔开:

prompt\u msg=输入一个数字: bad\u input\u msg=对不起,我不明白。 prompts=链[prompt\u msg],重复“\n”。加入[bad\u input\u msg,prompt\u msg] 回复=mapinput,提示 valid_response=nextfilterstr.isdigit,回复 打印有效的\u响应 输入一个数字:a 对不起,我不明白。 输入一个数字:b 对不起,我不明白。 输入一个数字:1 1. 它是如何工作的? prompts=chain[输入数字:],不是数字!再试一次: 和的组合将创建一个迭代器 这将产生字符串输入一个数字:一次,而不是一个数字!重试:无限次: 对于提示中的提示: 打印提示 输入一个数字: 不是数字!再试一次: 不是数字!再试一次: 不是数字!再试一次: ... 等等 replies=mapinput,prompts-此处将上一步中的所有提示字符串应用于函数。例如。: 在答复中答复: 打印答复 输入一个数字:a A. 不是数字!再试一次:1 1. 不是数字!再试一次:现在不管了 现在不在乎了 等等 我们使用和过滤掉那些只包含数字的字符串: 只有_digits=filterstr.isdigit,回复 对于仅以_位数字回复: 打印答复 输入一个数字:a 不是数字!再试一次:1 1. 不是数字!再试一次:2 2. 不是数字!再试一次:b 不是数字!再试一次:等等。。。 为了只得到第一个数字,我们只使用字符串。 其他验证规则: 字符串方法:当然,您可以使用其他字符串方法,比如只获取字母字符串,或者只获取大写字母。有关完整列表,请参阅

会员资格测试: 有几种不同的执行方法。其中之一是通过使用方法:

从itertools导入链,重复 水果={‘苹果’、‘橘子’、‘桃子’} prompts=chain[输入水果:],重复我不知道这个!再试一次: 回复=mapinput,提示 有效的\u响应=nextfilterfruits.\uuu包含\uuuuuu个响应 打印有效的\u响应 输入一个水果:1 我不知道这个!再试一次:foo 我不知道这个!再试一次:苹果 苹果 数字比较: 我们可以在这里使用一些有用的比较方法。例如,对于使用: Click是一个用于命令行界面的库,它提供了向用户请求有效响应的功能

简单的例子:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
请输入一个数字: A. 错误:a不是有效的浮点值 请输入一个数字: 10 10 请注意它是如何将字符串值自动转换为浮点值的

检查值是否在范围内: 提供了不同的服务。要获取特定范围内的数字,我们可以使用IntRange:

你几岁 A. 错误:a不是有效的整数 你几岁 0 错误:0不在1到120的有效范围内。 你几岁 5. 5. 我们也可以只指定一个限制,最小或最大:

你几岁 0 错误:0小于最小有效值14。 你几岁 18 18 会员资格测试: 使用click.Choice类型。默认情况下,此检查区分大小写

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
提供水果苹果、桃子、橘子: 香蕉 错误:无效选择:香蕉。选择苹果、桃子、橘子 提供水果苹果、桃子、橘子: 橙色 橙色 使用路径和文件: 使用click.Path类型,我们可以检查现有路径并解析它们:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
提供路径: 不存在 错误:路径不存在不存在。 提供路径: 现有文件夹 '/path/to/existing_文件夹 可以通过单击来读取和写入文件。文件:

在哪个文件中写入数据?:
您可以始终应用简单的if-else逻辑,并在代码中添加一个以上的if逻辑 还有一个for循环

尽管如此: 年龄=首次输入请输入您的年龄: 如果年龄大于等于18岁: 你可以在美国投票! 如果年龄<18岁且年龄>0: 你不能在美国投票。 其他: 打印错误的字符,输入必须是数字 持续
这将是一个无限的厕所,你将被要求无限期地进入这个年龄。

简单的解决方案是:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        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.")
        break
上述代码的解释: 有效年龄应为正值,且不应超过正常生理年龄,例如,最大年龄为120岁

我们可以询问用户年龄,如果年龄输入为负或大于120,我们认为是无效输入,并要求用户再试一次。 输入有效输入后,我们使用嵌套的if else语句检查年龄是否大于等于18岁,反之亦然,并在下面的代码中打印一条消息,说明用户是否有资格投票

年龄=λi,f:fi,finput请输入您的年龄:,λi,f:i如果i.isdigit else Finput请输入您的年龄:,f 打印如果intage>=18,您可以在美国投票,否则您不能在美国投票,结束= 如果您想进行最大限度的尝试,比如说3次,请使用下面的代码

年龄=λi,n,f:fi,n,finput请输入您的年龄:,1,λi,n,f:i如果i.isdigit else无如果n==3其他finput请输入您的年龄:,n+1,f Print如果年龄和年龄>=18岁,您可以在美国投票,否则您不能在美国投票,结束=
注意:这使用递归。

使用try-except处理错误并再次重复:

while True:
    try:
        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.")
    except Exception as e:
        print("please enter number")
是的,我晚了6年才开始使用isdigit检查字符串是否代表有效整数

可以使用递归函数

def ask():
    answer = input("Please enter amount to convert: ")
    if not answer.isdigit():
        print("Invalid")
        return ask()

    Gbp = int(answer)

ask()
或者一段时间

while True:
    answer = input("Please enter amount to convert: ")
    if not answer.isdigit():
        print("Invalid")
        continue

    Gbp = int(answer)


请注意,这段代码是递归的,但这里不需要递归,正如Kevin所说,它可能会毁掉你的堆栈。@PM2Ring-你是对的。但我在这里的目的只是想说明短路是如何最小化和美化长代码段的。为什么要将lambda赋值给变量,只需使用def即可。def fage:远比f=lambda age清晰:在某些情况下,您可能只需要使用一次age,然后就没有使用该函数。一个人可能想使用一个函数,然后在工作完成后将其扔掉。此外,这可能不是最好的方法,但它肯定是另一种方法,这也是我的解决方案的目的。@aaveg您如何将此代码转化为实际节省用户提供的时间?阅读它很有趣,有很多例子,值得称赞。被低估的教训:不要低估傻瓜的创造力!不管怎样,我不仅会把这两个问答都投了更高的票,因为它们都很棒,而且你还与迪基六号达成了交易。干得好,@Kevin。别估计傻瓜的创造力。。。和聪明的攻击者。DOS攻击对于这类事情来说是最容易的,但其他攻击可能是可能的。@JArunMani我不认为它的风格不好,但可能不太可读。实际上,每个循环只有一个输入,循环将变得非常短,但条件可能会变得相当长…@laundmo,当然,我会释放我写入公共域的代码块。在任何情况下都可以随意使用它们,无需我的明确许可或知情。关于非代码块部分,如果您想将我的整个答案粘贴到您正在编写的一本学习Python的书中,那么让我们谈谈版税-您忘记在每次循环后增加iCount值。这并不能真正回答问题。问题是在用户给出有效响应之前获得用户输入,而不是无限期。这是一个多么彻底和美妙的答案,解释分解非常好。使用您的风格,如何剥离空白并降低输入的大小写以进行成员资格测试?我不想创建一个必须同时包含大写和小写示例的集合。我还想考虑空白输入错误。@Austin I添加了一个关于预处理的新部分。看一看,这让我想起了ReactiveX。但也许这一点最初是受到函数式语言的启发的?请输入您的年龄:dickety six:与问题中所述的崩溃相同…谢谢,这是完美的。在有效范围内循环选择一个数字正是我想要的。我认为您的一条评论中有一个bug,应该是这样的注意:Python 2.7用户应该很好地协调行动并进行更新:-您缺少一个break语句,并且printplease-enter数字是不必要的。如果您已经检测到按键,为什么要允许输入字符并到处抛出错误,而您却可以默默地忽略它们,直到得到所需的数字?@Kebman您可以这样做,但用户可能不太清楚它们可以键入什么。您缺少函数的返回。返回递归调用,但该调用不返回任何值。。。而你,当循环是无限的…@Tomerikoo它递归地问,直到答案是有效的,我想这就是被问到的。我是故意的
以一种可以将任何代码放入递归函数或while循环的方式编写它。这实际上是为一个不同的问题编写的,这个问题被标记为与这个问题的重复,所以我将它发布在这里。我的意思是,您应该使用一些场景来测试代码。在第一种情况下,Gbp=intanswer可能会返回intanswer,而在第二种情况下,可能会在某个地方出现中断
def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()
def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)
import click

number = click.prompt('Please enter a number', type=float)
print(number)
age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
number = click.prompt('Please enter a number', type=int, default=42)
print(number)
while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        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.")
        break
while True:
    try:
        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.")
    except Exception as e:
        print("please enter number")
def ask():
    answer = input("Please enter amount to convert: ")
    if not answer.isdigit():
        print("Invalid")
        return ask()

    Gbp = int(answer)

ask()
while True:
    answer = input("Please enter amount to convert: ")
    if not answer.isdigit():
        print("Invalid")
        continue

    Gbp = int(answer)