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

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

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

946157 次浏览

最简单的实现方法是将input方法放入这时候循环中。当你得到坏的输入时使用continue,当你满意时使用break退出循环。

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

使用#EYZ0和except检测用户何时输入无法解析的数据。

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中使用它,这样你就可以处理这时循环了。

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个错误”,但你低估了傻瓜的聪明才智!

虽然接受的答案是惊人的。我也想分享一个快速解决这个问题的方法。(这也照顾了负年龄问题。)

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: ")))

附注:此代码适用于python 3. x。

为什么你会做一个while True,然后打破这个循环,而你也可以把你的需求放在这时语句中,因为你想要的只是一旦你有了年龄就停止?

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.

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

所以,我最近在搞类似的东西,我想出了以下解决方案,它使用一种方式来获取拒绝垃圾的输入,甚至在以任何逻辑方式检查之前。

read_single_keypress()礼貌https://stackoverflow.com/a/6599441/4532996

def read_single_keypress() -> str:
"""Waits for a single keypress on stdin.
-- from :: https://stackoverflow.com/a/6599441/4532996
"""


import termios, fcntl, sys, os
fd = sys.stdin.fileno()
# save old state
flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
attrs_save = termios.tcgetattr(fd)
# make raw - the way to do this comes from the termios(3) man page.
attrs = list(attrs_save) # copy the stored version to update
# iflag
attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
| termios.ISTRIP | termios.INLCR | termios. IGNCR
| termios.ICRNL | termios.IXON )
# oflag
attrs[1] &= ~termios.OPOST
# cflag
attrs[2] &= ~(termios.CSIZE | termios. PARENB)
attrs[2] |= termios.CS8
# lflag
attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
| termios.ISIG | termios.IEXTEN)
termios.tcsetattr(fd, termios.TCSANOW, attrs)
# turn off non-blocking
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
# read a single keystroke
try:
ret = sys.stdin.read(1) # returns a single character
except KeyboardInterrupt:
ret = 0
finally:
# restore old state
termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
return ret


def until_not_multi(chars) -> str:
"""read stdin until !(chars)"""
import sys
chars = list(chars)
y = ""
sys.stdout.flush()
while True:
i = read_single_keypress()
_ = sys.stdout.write(i)
sys.stdout.flush()
if i not in chars:
break
y += i
return y


def _can_you_vote() -> str:
"""a practical example:
test if a user can vote based purely on keypresses"""
print("can you vote? age : ", end="")
x = int("0" + until_not_multi("0123456789"))
if not x:
print("\nsorry, age can only consist of digits.")
return
print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")


_can_you_vote()

您可以找到完整的模块这里

示例:

$ ./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!
$ _

请注意,此实现的本质是一旦读取非数字的内容就会关闭标准输入。我没有在a之后按回车键,但我需要在数字之后按回车键。

您可以将其与同一模块中的thismany()函数合并,例如只允许三位数。

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

while True:
age = input("Please enter your age: ")
if age.isdigit():
age = int(age)
break
else:
print("Invalid number '{age}'. Try again.".format(age=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.")
def validate_age(age):
if age >=0 :
return True
return False


while True:
try:
age = int(raw_input("Please enter your age:"))
if validate_age(age): break
except ValueError:
print "Error: Invalid age."

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

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

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

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

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
Value = None
while Value == None or Value.isdigit() == False:
try:
Value = str(input(Message)).strip()
except Exception:
Value = None
return Value


# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
age = int(Input("Please enter your age: "))
# For terminating program, the user can use 0 key and enter it as an a value.
if age == 0:
print("Terminating ...")
exit(0)
        

if age >= 18 and age <=150:
print("You are able to vote in the United States!")
else:
print("You are not able to vote in the United States.")

您可以使输入语句成为同时True循环,以便它重复询问用户输入,然后在用户输入您想要的响应时中断该循环。您可以使用try和除了块来处理无效响应。

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)

我选择了显式的ifraise语句而不是assert, 因为断言检查可能被关闭, 而验证应该始终打开以提供健壮性。

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

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

好问题!您可以尝试以下代码。=)

这段代码使用ast.literal_eval()查找输入的数据类型age)。然后它遵循以下算法:

  1. 要求用户输入她/他的age

    1.1。如果agefloatint数据类型:

    • 检查是否age>=18。如果age>=18,打印适当的输出并退出。

    • 检查是否0<age<18。如果0<age<18,打印适当的输出并退出。

    • 如果age<=0,请用户再次输入年龄的有效数字,(回到步骤1。)

    1.2.如果age不是floatint数据类型,则要求用户再次输入她/他的年龄(回到步骤1。)

这是代码。

from ast import literal_eval


''' This function is used to identify the data type of input data.'''
def input_type(input_data):
try:
return type(literal_eval(input_data))
except (ValueError, SyntaxError):
return str


flag = True


while(flag):
age = raw_input("Please enter your age: ")


if input_type(age)==float or input_type(age)==int:
if eval(age)>=18:
print("You are able to vote in the United States!")
flag = False
elif eval(age)>0 and eval(age)<18:
print("You are not able to vote in the United States.")
flag = False
else: print("Please enter a valid number as your age.")


else: print("Sorry, I didn't understand that.")

使用递归函数的持久用户输入:

String

def askName():
return input("Write your name: ").strip() or askName()


name = askName()

整数

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)

功能方法或“看妈妈没有循环!”:

from itertools import chain, repeat


prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

或者,如果您想将“错误输入”消息与其他答案中的输入提示分开:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

它是如何工作的?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    
    itertools.chainitertools.repeat的组合将创建一个迭代器 这将产生字符串"Enter a number: "一次,和"Not a number! Try again: "无限次:
    for prompt in prompts:
    print(prompt)
    
    Enter a number:
    Not a number! Try again:
    Not a number! Try again:
    Not a number! Try again:
    # ... and so on
    
  2. replies = map(input, prompts)-这里map将把上一步中的所有prompts字符串应用于input函数。例如:
    for reply in replies:
    print(reply)
    
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
    
  3. 我们使用filterstr.isdigit过滤掉那些只包含数字的字符串:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
    print(reply)
    
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    
    为了只获取第一个数字,我们使用next

其他验证规则:

  1. 字符串方法:当然,您可以使用其他字符串方法,例如str.isalpha仅获取字母字符串,或str.isupper仅获取大写。有关完整列表,请参阅文档

  2. 会员测试:
    有几种不同的方法来执行它。其中之一是使用__contains__方法:

    from itertools import chain, repeat
    
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
    
  3. 数字比较:
    我们可以在这里使用一些有用的比较方法。例如,对于__lt__<):

    from itertools import chain, repeat
    
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0
    

    或者,如果您不喜欢使用dunder方法(dunder=双下划线),您可以始终定义自己的函数,或者使用operator模块中的函数。

  4. 路径存在:
    这里可以使用pathlib库及其Path.exists方法:

    from itertools import chain, repeat
    from pathlib import Path
    
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt
    

限制尝试次数:

如果你不想通过无限次询问用户来折磨他,你可以在itertools.repeat的调用中指定一个限制。这可以与为next函数提供默认值相结合:

from itertools import chain, repeat


prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

预处理输入数据:

有时,如果用户不小心提供了大写字母或字符串开头或结尾有空格,我们不想拒绝输入。为了考虑到这些简单的错误,我们可以通过应用str.lowerstr.strip方法预处理输入数据。例如,对于成员资格测试,代码如下所示:

from itertools import chain, repeat


fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

如果你有许多函数要用于预处理,使用执行函数组合的函数可能更容易。例如,使用这里中的一个:

from itertools import chain, repeat


from lz.functional import compose


fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

组合验证规则:

对于一个简单的情况,例如,当程序要求年龄在1到120之间时,可以添加另一个filter

from itertools import chain, repeat


prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

但是在规则很多的情况下,最好实现一个执行逻辑连词的函数。在下面的例子中,我将使用这里中的一个现成的:

from functools import partial
from itertools import chain, repeat


from lz.logical import conjoin




def is_one_letter(string: str) -> bool:
return len(string) == 1




rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]


prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

不幸的是,如果有人需要为每个失败案例定制消息,那么,恐怕没有漂亮功能方法。或者,至少,我找不到。

使用点击

点击是一个命令行界面库,它提供了向用户询问有效响应的功能。

简单的例子:

import click


number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number:
a
Error: a is not a valid floating point value
Please enter a number:
10
10.0

请注意它如何自动将字符串值转换为浮点数。

检查一个值是否在一个范围内:

提供了不同的自定义类型。要获得特定范围内的数字,我们可以使用IntRange

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?:
a
Error: a is not a valid integer
What's your age?:
0
Error: 0 is not in the valid range of 1 to 120.
What's your age?:
5
5

我们还可以指定其中一个限制,minmax

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?:
0
Error: 0 is smaller than the minimum valid value 14.
What's your age?:
18
18

会员测试:

使用click.Choice类型。默认情况下,此检查区分大小写。

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange):
banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange):
OrAnGe
orange

处理路径和文件:

使用click.Path类型,我们可以检查现有路径并解析它们:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path:
nonexistent
Error: Path "nonexistent" does not exist.
Provide path:
existing_folder
'/path/to/existing_folder

读取和写入文件可以通过click.File完成:

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())
In which file to write data?:
# <-- provided an empty string, which is an illegal name for a file
In which file to write data?:
some_file.txt
Which file you wanna read?:
nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?:
some_file.txt
Hello!

其他例子:

密码确认:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password:
······
Repeat for confirmation:
·
Error: the two entered values do not match
Enter password:
······
Repeat for confirmation:
······
qwerty

默认值:

在这种情况下,只需按输入(或您使用的任何键)而不输入值,就会为您提供默认值:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]:
a
Error: a is not a valid integer
Please enter a number [42]:
 

42

您始终可以应用简单的if-else逻辑,并在代码中添加一个if逻辑以及一个for循环。

while True:
age = int(input("Please enter your age: "))
if (age >= 18)  :
print("You are able to vote in the United States!")
if (age < 18) & (age > 0):
print("You are not able to vote in the United States.")
else:
print("Wrong characters, the input must be numeric")
continue

这将是一个无限的厕所,你会被要求无限期地进入这个时代。

下面的代码可能会有所帮助。

age=(lambda i,f: f(i,f))(input("Please enter your age: "),lambda i,f: i if i.isdigit() else f(input("Please enter your age: "),f))
print("You are able to vote in the united states" if int(age)>=18 else "You are not able to vote in the united states",end='')

如果你想有最大的尝试,说3,使用下面的代码

age=(lambda i,n,f: f(i,n,f))(input("Please enter your age: "),1,lambda i,n,f: i if i.isdigit() else (None if n==3 else f(input("Please enter your age: "),n+1,f)))
print("You are able to vote in the united states" if age and int(age)>=18 else "You are not able to vote in the united states",end='')

注意:这使用递归。

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

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

我是Unix哲学“做一件事并把它做好”的忠实粉丝。捕获用户输入和验证它是两个独立的步骤:

  • 使用get_input提示用户输入,直到输入确定
  • 使用可传递给get_inputvalidator函数进行验证

它可以像(Python 3.8+,使用海象运算符)一样简单:

def get_input(
prompt="Enter a value: ",
validator=lambda x: True,
error_message="Invalid input. Please try again.",
):
while not validator(value := input(prompt)):
print(error_message)
return value


def is_positive_int(value):
try:
return int(value) >= 0
except ValueError:
return False


if __name__ == "__main__":
val = get_input("Give a positive number: ", is_positive_int)
print(f"OK, thanks for {val}")

示例运行:

Give a positive number: -5
Invalid input. Please try again.
Give a positive number: asdf
Invalid input. Please try again.
Give a positive number:
Invalid input. Please try again.
Give a positive number: 42
OK, thanks for 42

在Python<3.8中,您可以像这样使用get_input

def get_input(
prompt="Enter a value: ",
validator=lambda x: True,
error_message="Invalid input. Please try again.",
):
while True:
value = input(prompt)
if validator(value):
return value
print(error_message)

您还可以处理KeyboardInterrupt并在终止应用程序之前打印一条友好的退出消息。如果需要,可以使用计数器来限制允许的重试。

使用isdigit()检查字符串是否表示有效整数。

您可以使用递归函数。

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


return int(answer)


Gdp = ask()

或者一个同时循环

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


Gbp = int(answer)

您可以尝试将其转换为整数,但如果不起作用,请用户重复。

while True:
age = input('Please enter your age: ')
try:
age_int = int(age)
if age_int >= 18:
print('You can vote in the United States!')
else:
print('You cannot vote in the United States.')
break
except:
print('Please enter a meaningful answer.')
        

只要用户没有输入有意义的答案,这时候循环就会运行,但如果有意义就会中断。