Yêu cầu người dùng nhập liệu cho đến khi họ đưa ra phản hồi hợp lệ


562

Tôi đang viết một chương trình chấp nhận đầu vào từ người dùng.

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

Chương trình hoạt động như mong đợi miễn là người dùng nhập dữ liệu có ý nghĩa.

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

Nhưng nó không thành công nếu người dùng nhập dữ liệu không hợp lệ:

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'

Thay vì gặp sự cố, tôi muốn chương trình yêu cầu nhập lại. Như thế này:

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!

Làm thế nào tôi có thể làm cho chương trình yêu cầu đầu vào hợp lệ thay vì bị sập khi nhập dữ liệu không nhạy cảm?

Làm thế nào tôi có thể từ chối các giá trị như -1, đó là một giá trị int, nhưng vô nghĩa trong bối cảnh này?

Câu trả lời:


704

Cách đơn giản nhất để thực hiện điều này là đưa inputphương thức vào một vòng lặp while. Sử dụng continuekhi bạn nhận được đầu vào xấu và breakra khỏi vòng lặp khi bạn hài lòng.

Khi đầu vào của bạn có thể tăng ngoại lệ

Sử dụng tryexcept phát hiện khi người dùng nhập dữ liệu không thể phân tích cú pháp.

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

Thực hiện các quy tắc xác nhận của riêng bạn

Nếu bạn muốn từ chối các giá trị mà Python có thể phân tích thành công, bạn có thể thêm logic xác thực của riêng bạn.

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

Kết hợp Xử lý ngoại lệ và Xác thực tùy chỉnh

Cả hai kỹ thuật trên có thể được kết hợp thành một vòng lặp.

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

Đóng gói tất cả trong một chức năng

Nếu bạn cần hỏi người dùng của mình nhiều giá trị khác nhau, có thể hữu ích khi đặt mã này vào một hàm, vì vậy bạn không phải nhập lại mã mỗi lần.

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

Để tất cả chúng cùng nhau

Bạn có thể mở rộng ý tưởng này để thực hiện một chức năng đầu vào rất chung chung:

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

Với cách sử dụng như:

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

Những cạm bẫy thường gặp và tại sao bạn nên tránh chúng

Việc sử dụng dự phòng của inputbáo cáo dự phòng

Phương pháp này hoạt động nhưng thường được coi là phong cách kém:

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

Nó có thể trông hấp dẫn ban đầu vì nó ngắn hơn while Truephương pháp, nhưng nó vi phạm nguyên tắc Không lặp lại của chính bạn về phát triển phần mềm. Điều này làm tăng khả năng xảy ra lỗi trong hệ thống của bạn. Điều gì sẽ xảy ra nếu bạn muốn backport thành 2.7 bằng cách thay đổi inputthành raw_input, nhưng vô tình chỉ thay đổi cái đầu tiên inputở trên? Đó SyntaxErrorchỉ là chờ đợi để xảy ra.

Đệ quy sẽ thổi bay ngăn xếp của bạn

Nếu bạn vừa tìm hiểu về đệ quy, bạn có thể muốn sử dụng nó get_non_negative_intđể bạn có thể loại bỏ vòng lặp 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

Điều này dường như hoạt động tốt hầu hết thời gian, nhưng nếu người dùng nhập dữ liệu không hợp lệ đủ số lần, tập lệnh sẽ chấm dứt với a RuntimeError: maximum recursion depth exceeded. Bạn có thể nghĩ rằng "không có kẻ ngốc nào sẽ phạm 1000 lỗi liên tiếp", nhưng bạn đang đánh giá thấp sự khéo léo của những kẻ ngốc!


53
Thật thú vị khi đọc nó với nhiều ví dụ, kudos. Bài học không thể chối cãi: "Đừng đánh giá thấp sự khéo léo của những kẻ ngốc!"
vpibano

3
Dù sao, tôi không chỉ nâng cao cả hai câu hỏi và trả lời, vì chúng rất tuyệt, nhưng bạn đã niêm phong thỏa thuận với "số sáu". Làm tốt lắm, @Kevin.
erekalper

1
Đừng ước tính sự khéo léo của những kẻ ngốc ... và những kẻ tấn công thông minh. Một cuộc tấn công DOS sẽ dễ dàng nhất cho loại điều này, nhưng những thứ khác có thể có thể.
Solomon Ucko

Chúng ta có thể sử dụng toán tử "hải mã" mới thay vì đầu vào dự phòng không? Có phải đó cũng là một phong cách nghèo nàn?
J Arun Mani

1
@JArunMani Tôi không nghĩ nó sẽ là phong cách kém, nhưng có thể ít đọc hơn một chút. Bạn thực sự sẽ chỉ có một inputvòng lặp và vòng lặp sẽ trở nên rất ngắn, nhưng điều kiện có thể trở nên khá dài ...
Tomerikoo

39

Tại sao bạn sẽ làm một while Truevà sau đó thoát ra khỏi vòng lặp này trong khi bạn cũng có thể chỉ đưa các yêu cầu của mình vào câu lệnh while vì tất cả những gì bạn muốn là dừng lại khi bạn có tuổi?

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

Điều này sẽ dẫn đến kết quả như sau:

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.

điều này sẽ hoạt động vì tuổi tác sẽ không bao giờ có giá trị sẽ không có ý nghĩa và mã tuân theo logic của "quy trình kinh doanh" của bạn


22

Mặc dù câu trả lời được chấp nhận là tuyệt vời. Tôi cũng muốn chia sẻ một bản hack nhanh cho vấn đề này. (Điều này cũng quan tâm đến vấn đề tuổi tác tiêu cực.)

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 Mã này dành cho python 3.x.


1
Lưu ý rằng mã này là đệ quy, nhưng đệ quy không cần thiết ở đây và như Kevin nói, nó có thể thổi bay ngăn xếp của bạn.
PM 2Ring

2
@ PM2Ring - bạn nói đúng. Nhưng mục đích của tôi ở đây chỉ là để cho thấy "ngắn mạch" có thể giảm thiểu (làm đẹp) các đoạn mã dài như thế nào.
aaveg

11
Tại sao bạn lại gán lambda cho một biến, chỉ sử dụng defthay thế. def f(age):rõ ràng hơn nhiều so vớif = lambda age:
GP89

3
Trong một số trường hợp, bạn có thể cần độ tuổi chỉ một lần và sau đó không sử dụng chức năng đó. Người ta có thể muốn sử dụng một chức năng và vứt nó đi sau khi hoàn thành công việc. Ngoài ra, đây có thể không phải là cách tốt nhất, nhưng nó chắc chắn là một cách làm khác (đó là mục đích của giải pháp của tôi).
aaveg

@aaveg làm thế nào bạn có thể biến mã này để thực sự tiết kiệm tuổi do người dùng cung cấp?
Tytire Recubans

12

Vì vậy, gần đây tôi đã loay hoay với một thứ tương tự như thế này và tôi đã đưa ra giải pháp sau, sử dụng cách lấy đầu vào từ chối rác, trước cả khi nó được kiểm tra theo bất kỳ cách logic nào.

read_single_keypress()lịch sự 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()

Bạn có thể tìm thấy các mô-đun hoàn chỉnh ở đây .

Thí dụ:

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

Lưu ý rằng bản chất của việc triển khai này là nó đóng stdin ngay khi một cái gì đó không phải là một chữ số được đọc. Tôi đã không nhấn enter sau a, nhưng tôi cần phải theo sau các con số.

Bạn có thể hợp nhất hàm này với thismany()hàm trong cùng một mô-đun để chỉ cho phép, giả sử, ba chữ số.


12

Phương pháp tiếp cận chức năng hoặc " nhìn mẹ không có vòng lặp! ":

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

hoặc nếu bạn muốn có một thông báo "đầu vào xấu" được tách ra khỏi dấu nhắc nhập như trong các câu trả lời khác:

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

Làm thế nào nó hoạt động?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    Sự kết hợp này itertools.chainitertools.repeatsẽ tạo ra một trình vòng lặp sẽ tạo ra chuỗi "Enter a number: "một lần và "Not a number! Try again: "số lần vô hạn:
    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)- ở đây mapsẽ áp dụng tất cả các promptschuỗi từ bước trước cho inputhàm. Ví dụ:
    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. Chúng tôi sử dụng filterstr.isdigitđể lọc ra những chuỗi chỉ chứa các chữ số:
    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...
    Và để chỉ lấy chuỗi chữ số đầu tiên - chúng tôi sử dụng next.

Các quy tắc xác nhận khác:

  1. Các phương thức chuỗi: Tất nhiên bạn có thể sử dụng các phương thức chuỗi khác như str.isalphachỉ nhận các chuỗi chữ cái hoặc str.isupperchỉ nhận được chữ hoa. Xem tài liệu cho danh sách đầy đủ.

  2. Kiểm tra thành viên:
    Có một số cách khác nhau để thực hiện nó. Một trong số đó là bằng __contains__phương pháp:

    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. So sánh số:
    Có các phương pháp so sánh hữu ích mà chúng ta có thể sử dụng ở đây. Ví dụ: cho __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

    Hoặc, nếu bạn không thích sử dụng các phương thức dunder (dunder = double-undererscore), bạn luôn có thể xác định chức năng của riêng mình hoặc sử dụng các phương thức từ operatormô-đun.

  4. Sự tồn tại của đường dẫn:
    Ở đây người ta có thể sử dụng pathlibthư viện và Path.existsphương thức của nó :

    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

Giới hạn số lần thử:

Nếu bạn không muốn hành hạ người dùng bằng cách hỏi anh ta một số lần vô hạn, bạn có thể chỉ định giới hạn trong một cuộc gọi itertools.repeat. Điều này có thể được kết hợp với việc cung cấp một giá trị mặc định cho nexthàm:

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!

Tiền xử lý dữ liệu đầu vào:

Đôi khi, chúng tôi không muốn từ chối đầu vào nếu người dùng vô tình cung cấp nó trong CAPS hoặc có khoảng trắng ở đầu hoặc cuối chuỗi. Để tính đến những lỗi đơn giản này, chúng ta có thể xử lý trước dữ liệu đầu vào bằng cách áp dụng str.lowerstr.stripphương pháp. Ví dụ, đối với trường hợp kiểm tra thành viên, mã sẽ như thế này:

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

Trong trường hợp khi bạn có nhiều hàm để sử dụng cho tiền xử lý, có thể dễ dàng hơn để sử dụng một hàm thực hiện một thành phần chức năng . Ví dụ: sử dụng một từ đây :

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

Kết hợp các quy tắc xác nhận:

Ví dụ, đối với một trường hợp đơn giản, khi chương trình yêu cầu độ tuổi từ 1 đến 120, người ta có thể chỉ cần thêm một trường hợp khác 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)

Nhưng trong trường hợp khi có nhiều quy tắc, tốt hơn là thực hiện một chức năng thực hiện kết hợp logic . Trong ví dụ sau tôi sẽ sử dụng một cái sẵn sàng từ đây :

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

Thật không may, nếu ai đó cần một thông điệp tùy chỉnh cho từng trường hợp thất bại, thì tôi sợ, không có cách nào khá hữu ích . Hoặc, ít nhất, tôi không thể tìm thấy một.


Thật là một câu trả lời thấu đáo và tuyệt vời, sự cố giải thích thật tuyệt vời.
Locane

Sử dụng phong cách của bạn, làm thế nào một người sẽ đi về tước bỏ khoảng trắng và hạ thấp đầu vào để thử nghiệm thành viên? Tôi không muốn tạo một bộ phải bao gồm cả ví dụ chữ hoa và chữ thường. Tôi cũng muốn cho phép các lỗi nhập khoảng trắng.
Austin

1
@Austin Tôi đã thêm một phần mới về tiền xử lý. Hãy xem.
Georgy

Điều đó làm tôi nhớ đến ReactiveX. Nhưng có lẽ điều đó đã được truyền cảm hứng bởi các ngôn ngữ chức năng ở nơi đầu tiên?
Mateen Ulhaq

8

Sử dụng Nhấp chuột :

Click là một thư viện cho các giao diện dòng lệnh và nó cung cấp chức năng để yêu cầu một phản hồi hợp lệ từ người dùng.

Ví dụ đơn giả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

Lưu ý cách nó tự động chuyển đổi giá trị chuỗi thành float.

Kiểm tra nếu một giá trị nằm trong một phạm vi:

Có nhiều loại tùy chỉnh khác nhau được cung cấp. Để có được một số trong một phạm vi cụ thể, chúng ta có thể sử dụng 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

Chúng tôi cũng có thể chỉ định một trong các giới hạn minhoặc max:

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

Thử nghiệm thành viên:

Sử dụng click.Choiceloại. Theo mặc định, kiểm tra này là trường hợp nhạy cảm.

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

Làm việc với các đường dẫn và tệp:

Sử dụng một click.Pathloại chúng ta có thể kiểm tra các đường dẫn hiện có và cũng giải quyết chúng:

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

Đọc và viết các tập tin có thể được thực hiện bằng cách 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!

Những ví dụ khác:

Xác nhận mật khẩu:

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

Giá trị mặc định:

Trong trường hợp này, chỉ cần nhấn Enter(hoặc bất kỳ phím nào bạn sử dụng) mà không nhập giá trị, sẽ cung cấp cho bạn một mặc định:

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

3
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."

2

Dựa trên những gợi ý tuyệt vời của Daniel Q và Patrick Artner, đây là một giải pháp thậm chí còn khái quát hơn.

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

Tôi đã chọn cho các tuyên bố rõ ràng ifraisethay vì một assert, bởi vì kiểm tra xác nhận có thể bị tắt, trong khi xác nhận phải luôn luôn được bật để cung cấp sự mạnh mẽ.

Điều này có thể được sử dụng để có được các loại đầu vào khác nhau, với các điều kiện xác nhận khác nhau. Ví dụ:

# 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!"})

Hoặc, để trả lời câu hỏi ban đầu:

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

Hãy thử cái này: -

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

0

Trong khi một khối try/ exceptsẽ hoạt động, một cách nhanh hơn và sạch hơn để hoàn thành nhiệm vụ này sẽ là sử dụng 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.")

0

Câu hỏi hay! Bạn có thể thử mã sau đây cho việc này. =)

Mã này sử dụng ast.literal_eval () để tìm kiểu dữ liệu của đầu vào ( age). Sau đó, nó theo thuật toán sau:

  1. Yêu cầu người dùng nhập liệu của anh ấy / anh ấy age.

    1.1. Nếu agefloathoặc intkiểu dữ liệu:

    • Kiểm tra nếu age>=18. Nếu age>=18, in đầu ra và thoát thích hợp.

    • Kiểm tra nếu 0<age<18. Nếu 0<age<18, in đầu ra và thoát thích hợp.

    • Nếu age<=0, yêu cầu người dùng nhập lại một số hợp lệ cho tuổi, ( tức là quay lại bước 1.)

    1.2. Nếu agekhông phải là floathay intkiểu dữ liệu, sau đó yêu cầu người dùng nhập vào cô / tuổi của mình một lần nữa ( tức là quay trở lại bước 1.)

Đây là mã.

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

0

Bạn luôn có thể áp dụng logic if-other đơn giản và thêm một iflogic nữa vào mã của bạn cùng với một forvòng lặp.

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

Đây sẽ là một loo vô hạn và bạn sẽ được yêu cầu nhập tuổi, vô thời hạn.


Điều này không thực sự trả lời câu hỏi. Câu hỏi là về việc nhận được đầu vào của người dùng cho đến khi họ đưa ra phản hồi hợp lệ, không phải là vô thời hạn .
Georgy

-1

Bạn có thể viết logic tổng quát hơn để cho phép người dùng chỉ nhập số lần cụ thể, vì cùng một trường hợp sử dụng phát sinh trong nhiều ứng dụng trong thế giới thực.

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.

1
bạn quên tăng giá trị iCount sau mỗi vòng lặp
Hoài-Thu Vương

-1

Bạn có thể thực hiện câu lệnh đầu vào một vòng lặp True để nó liên tục yêu cầu đầu vào của người dùng và sau đó ngắt vòng lặp đó nếu người dùng nhập phản hồi bạn muốn. Và bạn có thể sử dụng thử và ngoại trừ các khối để xử lý các phản hồi không hợp lệ.

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

Biến var chỉ là để nếu người dùng nhập một chuỗi thay vì số nguyên, chương trình sẽ không trả về "Bạn không thể bỏ phiếu tại Hoa Kỳ."


-1

Sử dụng câu lệnh "while" cho đến khi người dùng nhập một giá trị thực và nếu giá trị đầu vào không phải là số hoặc đó là giá trị null bỏ qua nó và thử hỏi lại, v.v. Trong ví dụ tôi đã cố gắng trả lời thực sự câu hỏi của bạn. Nếu chúng ta cho rằng tuổi của chúng ta nằm trong khoảng từ 1 đến 150 thì giá trị đầu vào được chấp nhận, nếu không thì đó là một giá trị sai. Để kết thúc chương trình, người dùng có thể sử dụng phím 0 và nhập nó làm giá trị.

Lưu ý: Đọc bình luận hàng đầu của mã.

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

-1

Thêm một giải pháp cho việc sử dụng xác thực đầu vào bằng cách sử dụng ValidationErrorxác thực phạm vi tùy chỉnh và (tùy chọn) cho đầu vào số nguyên:

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

Sử dụng:

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)

Đầu ra:

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

-1

Đây là một giải pháp tổng quát hơn, gọn gàng hơn, tránh các khối if / other lặp đi lặp lại: viết một hàm lấy các cặp (Lỗi, nhắc lỗi) trong từ điển và thực hiện tất cả các kiểm tra giá trị của bạn với các xác nhận.

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

Sử dụng:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

-1

Đầu vào người dùng liên tục sử dụng chức năng đệ quy :

Chuỗi

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

name = askName()

Số nguyên

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

age = askAge()

và cuối cùng, yêu cầu câu hỏi:

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)

-2

Giải pháp đơn giản sẽ là:

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

Giải thích về mã trên: Để có tuổi hợp lệ, nó phải dương và không nên nhiều hơn tuổi vật lý bình thường, ví dụ tuổi tối đa là 120.

Sau đó, chúng tôi có thể yêu cầu người dùng về độ tuổi và nếu đầu vào tuổi âm hoặc hơn 120, chúng tôi coi đó là đầu vào không hợp lệ và yêu cầu người dùng thử lại.

Khi đầu vào hợp lệ được nhập, chúng tôi sẽ thực hiện kiểm tra (sử dụng câu lệnh if-if lồng nhau) cho dù tuổi>> 18 hoặc ngược lại và in một thông báo cho dù người dùng có đủ điều kiện để bỏ phiếu


"Vui lòng nhập tuổi của bạn: tinh ranh sáu" ': cùng một vụ tai nạn như đã nêu trong câu hỏi ...
BDL

-2

lấy đầu vào dưới dạng chuỗi và sử dụng isdigit () để kiểm tra đầu vào chỉ có chữ số, không trống, không thể -ve

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False


Nó cũng không trả lời câu hỏi.
Georgy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.