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

Kev*_*vin 523 python validation loops user-input python-3.x

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

#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.")
Run Code Online (Sandbox Code Playgroud)

如果用户输入合理数据,这将按预期工作.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!
Run Code Online (Sandbox Code Playgroud)

但如果他们犯了错误,那就崩溃了:

C:\Python\Projects> canyouvote.py
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'
Run Code Online (Sandbox Code Playgroud)

而不是崩溃,我希望它再次尝试获取输入.像这样:

C:\Python\Projects> canyouvote.py
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!
Run Code Online (Sandbox Code Playgroud)

我怎么能做到这一点?如果我还想拒绝像这样的上下文中-1的有效int但无意义的值,该怎么办?

Kev*_*vin 641

实现此目的的最简单方法是将input方法放在while循环中.continue当你输入错误时使用,break当你满意时使用.

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

使用try和catch检测用户何时输入无法解析的数据.

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.")
Run Code Online (Sandbox Code Playgroud)

实施您自己的验证规则

如果要拒绝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
Run Code Online (Sandbox Code Playgroud)

结合异常处理和自定义验证

上述两种技术都可以组合成一个循环.

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.")
Run Code Online (Sandbox Code Playgroud)

将其全部封装在一个函数中

如果您需要向用户询问许多不同的值,将此代码放在函数中可能很有用,因此您不必每次都重新键入它.

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: ")
Run Code Online (Sandbox Code Playgroud)

把它放在一起

您可以扩展这个想法,以创建一个非常通用的输入函数:

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
Run Code Online (Sandbox Code Playgroud)

使用如下:

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

常见的陷阱,为什么你应该避免它们

冗余try语句的冗余使用

这种方法有效但通常被认为是不好的风格:

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): ")
Run Code Online (Sandbox Code Playgroud)

它最初看起来很有吸引力,因为它比except方法短,但它违反了软件开发的" 不要重复自己"的原则.这会增加系统中出现错误的可能性.如果你想通过更改inputwhile True,但仅意外更改input上面的第一个来向后移植到2.7,该怎么办?这是一个raw_input等待发生的事情.

递归会打击你的堆栈

如果你刚学会了递归,你可能会想要使用它,input这样你就可以处理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
Run Code Online (Sandbox Code Playgroud)

这似乎在大多数情况下都能正常工作,但如果用户输入的数据足够多次,脚本将以a终止SyntaxError.你可能会认为"没有傻瓜会连续犯1000个错误",但你低估了傻瓜的聪明才智!

  • 很有趣,阅读它有许多例子,荣誉.被低估的教训:"不要低估傻瓜的聪明才智!" (46认同)
  • @laundmo,当然我将我编写的代码块发布到公共领域。请在任何情况下随意使用它们,无需我的明确许可或不知情。关于非代码块段,如果您想将我的整个答案粘贴到您正在编写的“学习Python”书中,让我们谈谈版税;-) (4认同)
  • 不管怎么说,我不仅支持Q&A,因为它们很棒,但你用"摇摇欲坠的六"来达成协议.干得好,@凯文. (3认同)
  • 不要估计傻瓜的聪明才智……和聪明的攻击者。对于这类事情,DOS 攻击是最容易的,但其他攻击也是可能的。 (2认同)

小智 34

为什么你会做一个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.")
Run Code Online (Sandbox Code Playgroud)

这将导致以下结果:

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.
Run Code Online (Sandbox Code Playgroud)

这将有效,因为年龄永远不会有一个没有意义的价值,代码遵循你的"业务流程"的逻辑


aav*_*veg 22

虽然接受的答案是惊人的.我还想分享这个问题的快速入侵.(这也解决了负面年龄问题.)

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: ")))
Run Code Online (Sandbox Code Playgroud)

PS此代码适用于python 3.x.

  • 为什么要将lambda赋给变量,只需使用`def`.`def f(age):`远比`f = lambda age:`更清晰 (10认同)
  • 在某些情况下,您可能只需要一次年龄,然后就不会使用该功能.人们可能想要使用一个函数,并在完成工作后将其丢弃.此外,这可能不是最好的方式,但它肯定是一种不同的方式(这是我的解决方案的目的). (3认同)
  • @ PM2Ring-您是对的。但是我在这里的目的只是为了展示“短路”如何最小化(美化)长代码。 (2认同)

cat*_*cat 12

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

read_single_keypress()礼貌/sf/answers/461960901/

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()
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到完整的模块.

例:

$ ./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!
$ _
Run Code Online (Sandbox Code Playgroud)

请注意,此实现的性质是,只要读取非数字的内容,它就会关闭stdin.之后我没有进入a,但我需要在数字之后.

您可以将其与thismany()同一模块中的函数合并为仅允许三位数.


Geo*_*rgy 8

功能性方法或“ 看起来没有循环! ”:

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)
Run Code Online (Sandbox Code Playgroud)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    
    Run Code Online (Sandbox Code Playgroud) 的组合itertools.chainitertools.repeat将创建一个迭代器,这将产生串"Enter a number: "一次,"Not a number! Try again: "中无数次:
    for prompt in prompts:
        print(prompt)
    
    Run Code Online (Sandbox Code Playgroud)
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
    
    Run Code Online (Sandbox Code Playgroud)
  2. replies = map(input, prompts)-这里map会将prompts上一步中的所有字符串应用于input函数。例如:
    for reply in replies:
        print(reply)
    
    Run Code Online (Sandbox Code Playgroud)
    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...
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我们使用filterstr.isdigit过滤掉那些只包含数字的字符串:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    
    Run Code Online (Sandbox Code Playgroud)
    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...
    
    Run Code Online (Sandbox Code Playgroud) 并且仅使用第一个数字字符串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)
    
    Run Code Online (Sandbox Code Playgroud)
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
    
    Run Code Online (Sandbox Code Playgroud)
  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)
    
    Run Code Online (Sandbox Code Playgroud)
    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
    
    Run Code Online (Sandbox Code Playgroud)

    或者,如果您不喜欢使用dunder方法(dunder = double-underscore),则始终可以定义自己的函数,或使用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)
    
    Run Code Online (Sandbox Code Playgroud)
    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
    
    Run Code Online (Sandbox Code Playgroud)

限制尝试次数:

如果您不想无限次地问某人来折磨他,可以在呼叫中指定一个限制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!')
Run Code Online (Sandbox Code Playgroud)
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!
Run Code Online (Sandbox Code Playgroud)

预处理输入数据:

有时,如果用户不小心以大写形式提供了输入,或者在字符串的开头或结尾有空格,我们就不想拒绝输入。为了考虑这些简单的错误,我们可以通过应用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)
Run Code Online (Sandbox Code Playgroud)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange
Run Code Online (Sandbox Code Playgroud)

如果要使用许多函数进行预处理,则使用执行函数合成的函数可能会更容易。例如,使用此处的一个:

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)
Run Code Online (Sandbox Code Playgroud)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach
Run Code Online (Sandbox Code Playgroud)

合并验证规则:

例如,在一个简单的情况下,当程序要求输入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)
Run Code Online (Sandbox Code Playgroud)

但是,在有很多规则的情况下,最好实现执行逻辑结合的函数。在下面的例子中我将使用一个现成的一个位置

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)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果有人需要为每个失败的情况下,自定义消息,然后,我很害怕,也没有漂亮的功能性的方式。或者,至少,我找不到一个。


小智 7

使用 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")
Run Code Online (Sandbox Code Playgroud)

  • 您缺少“break”语句,并且“print("请输入数字")”是不必要的。 (4认同)

Joã*_*ues 6

基于 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)
Run Code Online (Sandbox Code Playgroud)

我选择了显式的ifandraise语句而不是 an 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!"})
Run Code Online (Sandbox Code Playgroud)

或者,回答原来的问题:

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.")
Run Code Online (Sandbox Code Playgroud)


np8*_*np8 6

是的,我迟到了 6 年, 但这个问题值得更多最新的答案。

关注点分离

我是 Unix 哲学“做一件事,把它做好”的忠实粉丝。在这种类型的问题中,更好的做法是将问题拆分为

  • 询问输入get_input直到输入正常。
  • validator功能上验证。您可以为不同的输入查询编写不同的验证器。

征求意见

它可以像(Python 3+)一样简单

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

def get_input(prompt, validator, on_validationerror):
    while True:
        value = input(prompt)
        if validator(value):
            return value
        print(on_validationerror)
Run Code Online (Sandbox Code Playgroud)

例子

In [2]: get_input('Give a positive number: ', myvalidator, 'Please, try again')
Give a positive number: foobar
Please, try again
Give a positive number: -10
Please, try again
Give a positive number: 42
Out[2]: '42'
Run Code Online (Sandbox Code Playgroud)

Python 3.8+ 注意

在 Python 3.8+ 中,您可以使用 walrus 运算符

def get_input(prompt, validator, on_validationerror):
    while not validator(value := input(prompt)):
        print(on_validationerror)
    return value 
Run Code Online (Sandbox Code Playgroud)


小智 5

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."
Run Code Online (Sandbox Code Playgroud)


Geo*_*rgy 5

使用点击

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

简单的例子:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Run Code Online (Sandbox Code Playgroud)
import click

number = click.prompt('Please enter a number', type=float)
print(number)
Run Code Online (Sandbox Code Playgroud)

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

检查值是否在范围内:

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

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
Run Code Online (Sandbox Code Playgroud)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0
Run Code Online (Sandbox Code Playgroud)

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

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
Run Code Online (Sandbox Code Playgroud)
age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
Run Code Online (Sandbox Code Playgroud)

会员资格测试:

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

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

使用路径和文件:

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

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Run Code Online (Sandbox Code Playgroud)
age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
Run Code Online (Sandbox Code Playgroud)

读写文件可以通过以下方式完成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())
Run Code Online (Sandbox Code Playgroud)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18
Run Code Online (Sandbox Code Playgroud)

其他例子:

确认密码:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Run Code Online (Sandbox Code Playgroud)
choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Run Code Online (Sandbox Code Playgroud)

默认值:

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

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Run Code Online (Sandbox Code Playgroud)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange
Run Code Online (Sandbox Code Playgroud)