Запрашивать у пользователя ввод, пока он не даст верный ответ

Apr 25 2014

Я пишу программу, которая принимает ввод от пользователя.

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

Программа работает должным образом, пока пользователь вводит значимые данные.

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

Но это не удается, если пользователь вводит недопустимые данные:

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'

Вместо сбоя я хотел бы, чтобы программа снова запрашивала ввод. Как это:

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!

Как я могу заставить программу запрашивать действительные входные данные вместо сбоя при вводе несущественных данных?

Как я могу отклонить такие значения, как -1, что является допустимым int, но бессмысленным в данном контексте?

Ответы

776 Kevin Apr 25 2014 at 20:31

Самый простой способ добиться этого - поместить inputметод в цикл while. Используйте, continueкогда вы получаете неверный ввод, и breakвыходите из цикла, когда вас устраивает.

Когда ваш ввод может вызвать исключение

Используйте tryи,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метод, но это нарушает принцип разработки программного обеспечения « Не повторяйся» . Это увеличивает вероятность ошибок в вашей системе. Что делать , если вы хотите , чтобы портировать до 2,7 путем изменения inputв raw_input, но случайно изменить только первый inputвыше? Это SyntaxErrorпросто ожидание.

Рекурсия взорвет ваш стек

Если вы только что узнали о рекурсии, у вас может возникнуть соблазн использовать ее, 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

Похоже, что большую часть времени это работает нормально, но если пользователь вводит недопустимые данные достаточно много раз, сценарий завершается с расширением RuntimeError: maximum recursion depth exceeded. Вы можете думать, что «ни один дурак не сделает 1000 ошибок подряд», но вы недооцениваете изобретательность глупцов!

46 StevenStip Jan 14 2016 at 19:43

Зачем вам делать, 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.")

Это приведет к следующему:

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.

это будет работать, так как возраст никогда не будет иметь значения, которое не имеет смысла, а код следует логике вашего «бизнес-процесса»

26 aaveg Jun 29 2015 at 06:29

Хотя принятый ответ потрясающий. Я также хотел бы поделиться быстрым советом по этой проблеме. (Это также решает проблему отрицательного возраста.)

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 Этот код предназначен для python 3.x.

17 Georgy May 10 2019 at 23:47

Функциональный подход или « смотри маме без петель! »:

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.chainи itertools.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. Мы используем filterи str.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.lowerи str.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

К сожалению, если кому-то нужно индивидуальное сообщение для каждого неудачного случая, то, боюсь, довольно функционального способа не существует. Или, по крайней мере, я не мог его найти.

13 cat Jan 31 2016 at 10:47

Итак, я недавно возился с чем-то похожим на это, и я придумал следующее решение, которое использует способ получения ввода, который отклоняет мусор, прежде чем он даже будет проверен каким-либо логическим способом.

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

Обратите внимание, что природа этой реализации заключается в том, что stdin закрывается, как только считывается что-то, не являющееся цифрой. Я не нажимал ввод после a, но мне нужно было после цифр.

Вы можете объединить это с thismany()функцией в том же модуле, чтобы разрешить, скажем, только три цифры.

12 Georgy May 11 2019 at 03:17

Используя Click :

Click - это библиотека для интерфейсов командной строки, которая предоставляет функциональные возможности для запроса действительного ответа от пользователя.

Простой пример:

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

Мы также можем указать только одно из ограничений minили 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

Тестирование членства:

Используя 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

Значения по умолчанию:

В этом случае простое нажатие Enter(или любой другой клавиши) без ввода значения даст вам значение по умолчанию:

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 ojasmohril Jun 23 2016 at 17:34
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 JoãoManuelRodrigues Nov 28 2018 at 21:52

Основываясь на прекрасных предложениях Дэниела Кью и Патрика Артнера, вот еще более обобщенное решение.

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

Я выбрал для явных ifи raiseзаявлений вместо 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.")
1 PratikAnand Apr 30 2017 at 16:29

Попробуй это:-

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 np8 Oct 30 2020 at 14:12

Да , я 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)

пример

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'

Примечание Python 3.8+

В Python 3.8+ вы можете использовать оператор моржа

def get_input(prompt, validator, on_validationerror):
    while not validator(value := input(prompt)):
        print(on_validationerror)
    return value 
2Cubed May 31 2016 at 03:47

Хотя блок 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.")
SiddharthSatpathy Dec 18 2018 at 13:17

Хороший вопрос! Для этого вы можете попробовать следующий код. знак равно

Этот код использует ast.literal_eval (), чтобы найти тип данных input ( age). Далее следует следующий алгоритм:

  1. Попросите пользователя ввести ее / его age.

    1.1. Если ageесть floatили intтип данных:

    • Проверить, если age>=18. Если age>=18, распечатайте соответствующий вывод и выйдите.

    • Проверить, если 0<age<18. Если 0<age<18, распечатайте соответствующий вывод и выйдите.

    • Если age<=0попросить пользователя снова ввести действительное число возраста ( т.е. вернуться к шагу 1.)

    1.2. Если ageнет floatили intтип данных, попросите пользователя снова ввести свой возраст ( т.е. вернитесь к шагу 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.") 
Ep1c1aN Jul 01 2019 at 16:36

Вы всегда можете применить простую логику 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

Это будет бесконечный цикл, и вас попросят ввести возраст на неопределенный срок.

Liju Aug 17 2020 at 15:24

Код ниже может помочь.

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

Примечание: здесь используется рекурсия.

behnaz.sheikhi Sep 09 2020 at 19:30

Используйте 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")