询问用户输入,直到他们给出有效的响应
我正在编写一个接受用户输入的程序。
#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
)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(23)
尽管被接受的答案是惊人的。我还想分享解决此问题的快速技巧。 (这也解决了负年龄问题。)
PS 此代码适用于 python 3.x。
Though the accepted answer is amazing. I would also like to share a quick hack for this problem. (This takes care of the negative age problem as well.)
P.S. This code is for python 3.x.
使用点击:
点击是一个命令行界面库,它提供了向用户询问有效响应的功能。
简单的例子:
注意它如何自动将字符串值转换为浮点数。
检查值是否在范围内:
有不同的自定义类型 提供。要获取特定范围内的数字,我们可以使用
IntRange
:我们还可以仅指定限制之一,
min
或max
:成员资格测试:
使用
click.Choice
类型。默认情况下,此检查区分大小写。使用路径和文件:
使用
click.Path
类型,我们可以检查现有路径并解析它们:可以通过
click.File
来读取和写入文件:其他示例:
密码确认:
默认值:
在这种情况下,只需按 Enter (或您使用的任何键)而不输入值,将为您提供默认值:
Using Click:
Click is a library for command-line interfaces and it provides functionality for asking a valid response from a user.
Simple example:
Note how it converted the string value to a float automatically.
Checking if a value is within a range:
There are different custom types provided. To get a number in a specific range we can use
IntRange
:We can also specify just one of the limits,
min
ormax
:Membership testing:
Using
click.Choice
type. By default this check is case-sensitive.Working with paths and files:
Using a
click.Path
type we can check for existing paths and also resolve them:Reading and writing files can be done by
click.File
:Other examples:
Password confirmation:
Default values:
In this case, simply pressing Enter (or whatever key you use) without entering a value, will give you a default one:
我是 Unix 哲学“做一件事并把它做好”的忠实粉丝。捕获用户输入并验证它是两个独立的步骤:
get_input
提示用户输入,直到输入正确 使用的
validator
函数进行验证get_input它可以保持简单(Python 3.8+,带有海象运算符):
示例运行:
在Python中< 3.8 您可以像这样使用
get_input
:您还可以处理
KeyboardInterrupt
并在终止应用程序之前打印一条友好的退出消息。如果需要,可以使用计数器来限制允许的重试次数。I am a big fan of Unix philosophy "Do one thing and do it well". Capturing user input and validating it are two separate steps:
get_input
until the input is okvalidator
function that can be passed toget_input
It can be kept as simple as (Python 3.8+, with the walrus operator):
Sample run:
In Python < 3.8 you could use
get_input
like this:You might also handle
KeyboardInterrupt
and print a friendly exit message before terminating the application. A counter can be used to limit the allowed retries if desired.所以,我最近在搞类似的事情,我想出了以下解决方案,它使用一种获取拒绝垃圾输入的方法,甚至在以任何逻辑方式检查它之前。
read_single_keypress()
礼貌 https://stackoverflow.com/a/6599441/4532996您可以此处找到完整的模块。
示例:
请注意,此实现的本质是,一旦读取到非数字内容,它就会关闭标准输入。我没有在
a
之后按 Enter,但我需要在数字之后按 Enter。您可以将其与同一模块中的 thismany() 函数合并,以仅允许三位数字。
So, I was messing around with something similar to this recently, and I came up with the following solution, which uses a way of getting input that rejects junk, before it's even checked in any logical way.
read_single_keypress()
courtesy https://stackoverflow.com/a/6599441/4532996You can find the complete module here.
Example:
Note that the nature of this implementation is it closes stdin as soon as something that isn't a digit is read. I didn't hit enter after
a
, but I needed to after the numbers.You could merge this with the
thismany()
function in the same module to only allow, say, three digits.使用 try-except 处理错误并再次重复:
Use try-except to handle the error and repeat it again:
基于 Daniel Q 和 Patrick Artner 的出色建议,
这是一个更通用的解决方案。
我选择显式的
if
和raise
语句而不是assert
,因为断言检查可能被关闭,
而验证应始终开启以提供稳健性。
这可用于获取不同类型的输入,
具有不同的验证条件。
例如:
或者,回答原来的问题:
Building upon Daniel Q's and Patrick Artner's excellent suggestions,
here is an even more generalized solution.
I opted for explicit
if
andraise
statements instead of anassert
,because assertion checking may be turned off,
whereas validation should always be on to provide robustness.
This may be used to get different kinds of input,
with different validation conditions.
For example:
Or, to answer the original question:
好问题!您可以尝试以下代码。 =)
此代码使用 ast.literal_eval() 来查找输入的数据类型 (
age
)。然后它遵循以下算法:这是代码。
Good question! You can try the following code for this. =)
This code uses ast.literal_eval() to find the data type of the input (
age
). Then it follows the following algorithm:Here is the code.
试试这个:-
Try this one:-
使用“while”语句直到用户输入一个真值,如果输入值不是数字或者是空值,则跳过它并尝试再次询问,依此类推。
例如,我试图真实地回答你的问题。如果我们假设我们的年龄在 1 到 150 之间,则接受输入值,否则它是错误的值。
要终止程序,用户可以使用 0 键并将其输入为值。
Use "while" statement till user enter a true value and if the input value is not a number or it's a null value skip it and try to ask again and so on.
In example I tried to answer truly your question. If we suppose that our age is between 1 and 150 then input value accepted, else it's a wrong value.
For terminating program, the user can use 0 key and enter it as a value.
要通过验证和重试处理数字输入,请考虑使用 中的
int_input
函数typed-input
1 库(其他函数,如float_input
、decimal_input
和还提供了datetime_input
)。它简化了输入验证,确保类型安全,并为错误处理和自定义消息提供内置支持 - 所有这些都无需您自己编写重复的验证循环。安装
通过 pip 安装
typed-input
库:这是使用
int_input
的程序的更简洁版本:示例用法:
为什么使用
typed -输入
?min_value
、max_value
)和自定义错误消息以获得更好的指导。1 披露:我是
typed-input
。
To handle numeric input with validation and retries, consider using the
int_input
function from thetyped-input
1 library (other functions likefloat_input
,decimal_input
, anddatetime_input
are also provided). It simplifies input validation, ensures type safety, and provides built-in support for error handling and custom messages—all without writing repetitive validation loops yourself.Installation
Install the
typed-input
library via pip:Here’s a cleaner version of your program using
int_input
:Example Usage:
Why use
typed-input
?min_value
,max_value
) and custom error messages for better guidance.1 Disclosure: I am the author of
typed-input
.您始终可以应用简单的 if-else 逻辑,并在代码中再添加一个
if
逻辑以及for
循环。这将是一个无限的厕所,你会被要求无限期地进入这个时代。
You can always apply simple if-else logic and add one more
if
logic to your code along with afor
loop.This will be an infinite loo and you would be asked to enter the age, indefinitely.
虽然
try
/except
块可以工作,但完成此任务的更快、更简洁的方法是使用str.isdigit()
。While a
try
/except
block will work, a much faster and cleaner way to accomplish this task would be to usestr.isdigit()
.您可以编写更通用的逻辑,以允许用户仅输入特定次数,因为许多实际应用程序中都会出现相同的用例。
You can write more general logic to allow user to enter only specific number of times, as the same use-case arises in many real-world applications.
您可以将输入语句设置为 while True 循环,以便它重复要求用户输入,然后在用户输入您想要的响应时中断该循环。您可以使用 try 和 except 块来处理无效响应。
var 变量的作用是,如果用户输入字符串而不是整数,程序将不会返回“您无法在美国投票”。
You can make the input statement a while True loop so it repeatedly asks for the users input and then break that loop if the user enters the response you would like. And you can use try and except blocks to handle invalid responses.
The var variable is just so that if the user enters a string instead of a integer the program wont return "You are not able to vote in the United States."
另一种使用输入验证的解决方案,使用自定义的 ValidationError 和整数输入的(可选)范围验证:
用法:
输出:
One more solution for using input validation using a customized
ValidationError
and a (optional) range validation for integer inputs:Usage:
Output:
使用递归函数持久用户输入:
字符串
整数
,最后是问题要求:
Persistent user input using recursive function:
String
Integer
and finally, the question requirement:
您可以尝试将其转换为整数,但如果不起作用,请要求用户重复。
只要用户没有输入有意义的答案,while 循环就会运行,但如果有意义则循环会中断。
You can try to convert it to a integer, but ask the user to repeat if it doesn't work.
The while loop runs as long as the user has not inputted a meaningful answer, but breaks if it makes sense.
使用
isdigit()
来检查字符串是否代表有效的整数。您可以使用递归函数。
或者 while 循环
Use
isdigit()
to check if a string represents a valid integer.You could use a recursive function.
Or a while loop
下面的代码可能会有所帮助。
如果您想要最大尝试次数,例如 3 次,请使用下面的代码
注意:这使用递归。
Below code may help.
If you want to have maximum tries, say 3, use below code
Note: This uses recursion.
实现此目的的最简单方法是将
input
方法放入 while 循环中。使用继续
,当你满意时break
退出循环。当您的输入可能引发异常时,
请使用
try
并except
来检测用户何时输入无法解析的数据。实现您自己的验证规则
如果您想拒绝 Python 可以成功解析的值,您可以添加您自己的验证逻辑。
结合异常处理和自定义验证
上述两种技术都可以结合到一个循环中。
将其全部封装在一个函数中
如果您需要向用户询问许多不同的值,则将此代码放入一个函数中可能会很有用,这样您就不必每次都重新输入它。
将它们放在一起
您可以扩展这个想法来创建一个非常通用的输入函数:
用法如下:
常见陷阱,以及为什么应该避免它们
冗余
input
语句的冗余使用此方法有效,但通常被认为是糟糕的风格:
它最初可能看起来很有吸引力,因为它比
while True
方法短,但它违反了 不要重复自己软件开发原则。这会增加系统出现错误的可能性。如果您想通过将input
更改为raw_input
来向后移植到 2.7,但不小心只更改了上面的第一个input
该怎么办?这是一个正在等待发生的SyntaxError
。递归会让你的堆栈崩溃
如果您刚刚了解了递归,您可能会想在
get_non_negative_int
中使用它,这样您就可以处理 while 循环。这在大多数情况下似乎工作正常,但如果用户输入无效数据足够多次,脚本将终止并显示
运行时错误:超出最大递归深度
。你可能会认为“没有傻瓜会连续犯1000个错误”,但你低估了傻瓜的聪明才智!The simplest way to accomplish this is to put the
input
method in a while loop. Usecontinue
when you get bad input, andbreak
out of the loop when you're satisfied.When Your Input Might Raise an Exception
Use
try
andexcept
to detect when the user enters data that can't be parsed.Implementing Your Own Validation Rules
If you want to reject values that Python can successfully parse, you can add your own validation logic.
Combining Exception Handling and Custom Validation
Both of the above techniques can be combined into one loop.
Encapsulating it All in a Function
If you need to ask your user for a lot of different values, it might be useful to put this code in a function, so you don't have to retype it every time.
Putting It All Together
You can extend this idea to make a very generic input function:
With usage such as:
Common Pitfalls, and Why you Should Avoid Them
The Redundant Use of Redundant
input
StatementsThis method works but is generally considered poor style:
It might look attractive initially because it's shorter than the
while True
method, but it violates the Don't Repeat Yourself principle of software development. This increases the likelihood of bugs in your system. What if you want to backport to 2.7 by changinginput
toraw_input
, but accidentally change only the firstinput
above? It's aSyntaxError
just waiting to happen.Recursion Will Blow Your Stack
If you've just learned about recursion, you might be tempted to use it in
get_non_negative_int
so you can dispose of the while loop.This appears to work fine most of the time, but if the user enters invalid data enough times, the script will terminate with a
RuntimeError: maximum recursion depth exceeded
. You may think "no fool would make 1000 mistakes in a row", but you're underestimating the ingenuity of fools!为什么要执行 while True ,然后跳出这个循环,而您也可以将您的要求放入 while 语句中,因为您想要的只是在达到年龄后停止?
这将导致以下结果:
这将起作用,因为年龄永远不会有一个没有意义的值,并且代码遵循您的“业务流程”的逻辑
Why would you do a
while True
and then break out of this loop while you can also just put your requirements in the while statement since all you want is to stop once you have the age?This would result in the following:
this will work since age will never have a value that will not make sense and the code follows the logic of your "business process"
函数式方法或“看妈妈没有循环!”:
或如果您想像其他答案一样将“错误输入”消息与输入提示分开:
它是如何工作的?
itertools.chain
和 < 的组合a href="https://docs.python.org/library/itertools.html#itertools.repeat" rel="noreferrer">itertools.repeat
将创建一个迭代器这将产生字符串
"Enter a number: "
一次,以及"Not a number! Try Again: "
无限次:回复=地图(输入,提示)
- 这里map
会将上一步中的所有prompts
字符串应用到输入
函数。例如:filter
和str.isdigit
过滤掉那些只包含数字的字符串:为了仅获取第一个仅包含数字的字符串,我们使用
next
< /a>.其他验证规则:
字符串方法: 当然,您可以使用其他字符串方法,例如
str.isalpha
仅获取字母字符串,或str.isupper
仅获取大写字母。有关完整列表,请参阅文档。会员测试:
有几种不同的方法来执行它。其中之一是使用
__contains__
方法:数字比较:
我们可以在这里使用一些有用的比较方法。例如,对于
__lt__
(<
):或者,如果您不喜欢使用 dunder 方法(dunder = 双下划线),您可以随时定义自己的函数,或使用
operator
模块。路径存在:
这里可以使用
pathlib
库及其Path.exists
方法:限制尝试次数:
如果您不想通过无限次询问用户某件事来折磨用户,您可以在
itertools.repeat
。这可以与为next
函数:预处理输入数据:
有时,如果用户不小心提供了大写字母或在字符串开头或结尾带有空格,我们不想拒绝输入。为了考虑到这些简单的错误,我们可以通过应用
str 来预处理输入数据.lower
和str.strip
方法。例如,对于成员资格测试的情况,代码将如下所示:
如果您有许多函数可用于预处理,则使用执行 函数组合。例如,使用此处中的一个:
组合验证规则:
对于简单的情况,例如,当程序要求年龄在1到120之间时,可以添加另一个
过滤器
:但在规则很多的情况下,最好实现一个函数执行 逻辑合取。在下面的示例中,我将使用此处:
不幸的是,如果有人需要为每个失败的案例提供自定义消息,那么恐怕没有什么漂亮功能方法。或者,至少,我找不到一个。
Functional approach or "look mum no loops!":
or if you want to have a "bad input" message separated from an input prompt as in other answers:
How does it work?
This combination of
itertools.chain
anditertools.repeat
will create an iteratorwhich will yield strings
"Enter a number: "
once, and"Not a number! Try again: "
an infinite number of times:replies = map(input, prompts)
- heremap
will apply all theprompts
strings from the previous step to theinput
function. E.g.:filter
andstr.isdigit
to filter out those strings that contain only digits:And to get only the first digits-only string we use
next
.Other validation rules:
String methods: Of course you can use other string methods like
str.isalpha
to get only alphabetic strings, orstr.isupper
to get only uppercase. See docs for the full list.Membership testing:
There are several different ways to perform it. One of them is by using
__contains__
method:Numbers comparison:
There are useful comparison methods which we can use here. For example, for
__lt__
(<
):Or, if you don't like using dunder methods (dunder = double-underscore), you can always define your own function, or use the ones from the
operator
module.Path existance:
Here one can use
pathlib
library and itsPath.exists
method:Limiting number of tries:
If you don't want to torture a user by asking him something an infinite number of times, you can specify a limit in a call of
itertools.repeat
. This can be combined with providing a default value to thenext
function:Preprocessing input data:
Sometimes we don't want to reject an input if the user accidentally supplied it IN CAPS or with a space in the beginning or an end of the string. To take these simple mistakes into account we can preprocess the input data by applying
str.lower
andstr.strip
methods. For example, for the case of membership testing the code will look like this:In the case when you have many functions to use for preprocessing, it might be easier to use a function performing a function composition. For example, using the one from here:
Combining validation rules:
For a simple case, for example, when the program asks for age between 1 and 120, one can just add another
filter
:But in the case when there are many rules, it's better to implement a function performing a logical conjunction. In the following example I will use a ready one from here:
Unfortunately, if someone needs a custom message for each failed case, then, I'm afraid, there is no pretty functional way. Or, at least, I couldn't find one.