博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
要求用户提供输入,直到他们给出有效的答复
阅读量:2289 次
发布时间:2019-05-09

本文共 12945 字,大约阅读时间需要 43 分钟。

本文翻译自:

I am writing a program that accepts an input from the user. 我正在编写一个接受用户输入的程序。

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

The program works as expected as long as the the user enters meaningful data. 只要用户输入有意义的数据,该程序就会按预期运行。

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

But it fails if the user enters invalid data: 但是如果用户输入无效数据,它将失败:

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

Instead of crashing, I would like the program to ask for the input again. 除了崩溃,我希望程序再次请求输入。 Like this: 像这样:

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

How can I make the program ask for valid inputs instead of crashing when non-sensical data is entered? 输入非意义的数据时,如何使程序要求有效的输入而不是崩溃?

How can I reject values like -1 , which is a valid int , but nonsensical in this context? 如何拒绝像-1这样的值,它是一个有效的int ,但在这种情况下毫无意义?


#1楼

参考:


#2楼

The simplest way to accomplish this would be to put the input method in a while loop. 完成此操作的最简单方法是将input方法放入while循环中。 Use when you get bad input, and break out of the loop when you're satisfied. 使用当你错误的输入,并break循环了,当你满足。

When Your Input Might Raise an Exception 当您的输入可能引发异常时

Use to detect when the user enters data that can't be parsed. 使用来检测用户何时输入了无法解析的数据。

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.        breakif age >= 18:     print("You are able to vote in the United States!")else:    print("You are not able to vote in the United States.")

Implementing Your Own Validation Rules 实施您自己的验证规则

If you want to reject values that Python can successfully parse, you can add your own validation logic. 如果要拒绝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.        breakwhile 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

Combining Exception Handling and Custom Validation 结合异常处理和自定义验证

Both of the above techniques can be combined into one loop. 以上两种技术都可以组合成一个循环。

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.        breakif age >= 18:     print("You are able to vote in the United States!")else:    print("You are not able to vote in the United States.")

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. 如果您需要询问用户许多不同的值,则将此代码放在函数中可能很有用,因此您不必每次都重新键入。

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

Putting It All Together 全部放在一起

You can extend this idea to make a very generic input function: 您可以扩展此思想,以创建非常通用的输入函数:

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

With usage such as: 用法如下:

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

Common Pitfalls, and Why you Should Avoid Them 常见的陷阱以及为什么要避免它们

The Redundant Use of Redundant input Statements 冗余使用input语句

This method works but is generally considered poor style: 此方法有效,但通常被认为是较差的样式:

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

It might look attractive initially because it's shorter than the while True method, but it violates the principle of software development. 最初它看起来很有吸引力,因为它比while True方法短,但它违反了软件开发的“ 原理。 This increases the likelihood of bugs in your system. 这增加了系统中错误的可能性。 What if you want to backport to 2.7 by changing input to raw_input , but accidentally change only the first input above? 如果你想向移植到2.7通过改变inputraw_input ,却意外地只改变第一input上面? It's a SyntaxError just waiting to happen. 这是一个SyntaxError正等待发生。

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. 如果您刚刚了解了递归,则可能会想在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

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 . 这似乎在大多数情况下都可以正常工作,但是如果用户输入无效数据的次数足够多,该脚本将以RuntimeError: maximum recursion depth exceeded终止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! 您可能会认为“没有傻瓜会连续犯1000个错误”,但是您却低估了傻瓜的创造力!


#3楼

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.) (这也解决了负面的年龄问题。)

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

PS This code is for python 3.x. PS此代码适用于python3.x。


#4楼

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? 您为什么要做while True ,然后中断这个循环,而您也可以只将需求放在while语句中,因为您想要的只是一旦年龄就停止了?

age = Nonewhile 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.")

This would result in the following: 这将导致以下结果:

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

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" 这是可行的,因为年龄永远不会有没有意义的值,并且代码遵循“业务流程”的逻辑


#5楼

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 read_single_keypress()

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 retdef 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 ydef _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()

You can find the complete module . 您可以在找到完整的模块。

Example: 例:

$ ./input_constrain.pycan you vote? age : asorry, age can only consist of digits.$ ./input_constrain.py can you vote? age : 23
your age is 23You can vote!$ _

Note that the nature of this implementation is it closes stdin as soon as something that isn't a digit is read. 请注意,此实现的性质是,一旦读取到的不是数字,它就会关闭stdin。 I didn't hit enter after a , but I needed to after the numbers. 我没有在后面a回车,但我需要在数字后面。

You could merge this with the thismany() function in the same module to only allow, say, three digits. 您可以将其与thismany()函数合并到同一模块中,以仅允许输入三位数。


#6楼

While a try / except block will work, a much faster and cleaner way to accomplish this task would be to use str.isdigit() . 虽然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.")

转载地址:http://uscnb.baihongyu.com/

你可能感兴趣的文章
JVM 实战学习总结:JVM 的分代模型:年轻代、老年代、永久代
查看>>
面试官:聊聊 Spring 中的线程安全性
查看>>
一篇文教你在 Java 中利用 redis 实现分布式全局唯一标识服务
查看>>
深入浅出数据库事务和4种隔离级别
查看>>
对限频限流的思考
查看>>
15天内4面阿里,成功拿下offer,分享个人面经
查看>>
万字长文,带你深入浅出五种负载均衡策略。
查看>>
看图搞懂微服务架构
查看>>
详解:java工具之解析yaml文件
查看>>
包教包会:搭建RocketMQ双主双从同步集群,
查看>>
5年Java程序员,五面蚂蚁险拿offer定级P7,大厂面试不过如此?
查看>>
大厂面试必问!HashMap 怎样解决hash冲突?
查看>>
面试屡屡碰壁,痛定思痛闭关修炼!半年后4面阿里成功拿offer
查看>>
最全的大厂最新面试249题与笔记总结:多线程+JVM +Spring+微服务+分布式+Redis+MySQL
查看>>
吊!设计模式全解:6大设计原则+23种设计模式+设计模式PK+设计模式混编
查看>>
服!看完阿里大牛手写的Java异步编程实战笔记,我惊呆了
查看>>
Java程序员跳槽,三面之后被拒,原因竟是“招不起”
查看>>
想要彻底搞懂微服务架构?必先学:SpringBoot+SpringCloud+docker
查看>>
6天面试10家,已经拿到offer,Java程序员的面试总结分享
查看>>
渣本的逆袭之路!备战3个月,三面蚂蚁金服成功斩获Offer
查看>>