有効な応答が得られるまでユーザーに入力を求める

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

例外処理とカスタム検証の組み合わせ

上記の両方の手法を1つのループに組み合わせることができます。

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メソッドよりも短いので魅力的に見えるかもしれませんが、ソフトウェア開発の「Do n'tRepeatYourself」の原則に違反しています。これにより、システムにバグが発生する可能性が高くなります。に変更inputして2.7にバックポートしたい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ステートメントに要件を含めることもできますが、なぜaを実行してから、このループから抜け出すのでしょうか。

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このコードはPython3.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.chainitertools.repeat文字列が"Enter a number: "1回、"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)-ここでmapprompts、前の手順のすべての文字列をinput関数に適用します。例えば:
    for reply in replies:
        print(reply)
    
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
    
  3. を使用してfilterstr.isdigit数字のみを含む文字列を除外します。
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    
    そして、最初の桁のみを取得するために、文字列のみを使用しますnext

その他の検証ルール:

  1. 文字列メソッド:もちろんstr.isalpha、アルファベットの文字列str.isupperのみを取得したり、大文字のみを取得したりするなど、他の文字列メソッドを使用できます。完全なリストについては、ドキュメントを参照してください。

  2. メンバーシップテスト:
    それを実行するには、いくつかの異なる方法があります。それらの1つは、次の__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 = 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)
    
    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!

入力データの前処理:

ユーザーが誤って提供されている場合時々 、入力を拒否したくないCAPS INまたは文字列の先頭または末尾にスペースを。これらの単純な間違いを考慮に入れるためにstr.lowerstr.stripメソッドを適用して入力データを前処理することができます。たとえば、メンバーシップテストの場合、コードは次のようになります。

from itertools import chain, repeat

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

前処理に使用する関数が多い場合は、関数合成を実行する関数を使用する方が簡単な場合があります。たとえば、ここからのものを使用します

from itertools import chain, repeat

from lz.functional import compose

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

検証ルールの組み合わせ:

単純なケースの場合、たとえば、プログラムが1〜120歳を要求した場合、別の年齢を追加するだけで済みfilterます。

from itertools import chain, repeat

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

ただし、ルールが多い場合は、論理積を実行する関数を実装することをお勧めします。次の例では、ここから準備ができたものを使用します

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


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


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

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

残念ながら、誰かが失敗した各ケースのためのカスタムメッセージを必要とする場合、その後、私は怖い、何もありませんかなり機能的な方法は。または、少なくとも、私はそれを見つけることができませんでした。

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にEnterキーを押しませんでしたが、数字の後に入力する必要がありました。

これをthismany()同じモジュール内の関数とマージして、たとえば3桁のみを許可することができます。

12 Georgy May 11 2019 at 03:17

クリックの使用:

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

文字列値を自動的にfloatに変換したことに注意してください。

値が範囲内にあるかどうかの確認:

さまざまなカスタムタイプが提供されています。特定の範囲の数値を取得するには、次を使用できます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

制限の1つだけを指定することもできます、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

DanielQとPatrickArtnerの優れた提案に基づいて、さらに一般化されたソリューションを次に示します。

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

アサーションチェックがオフになっている可能性があるのに対し、堅牢性を提供するには検証を常にオンにする必要があるため、の代わりに明示的なステートメントifraiseステートメントを選択しましたassert

これは、さまざまな検証条件で、さまざまな種類の入力を取得するために使用できます。例えば:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

または、元の質問に答えるには:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")
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哲学「1つのことをしてうまくやる」の大ファンです。このタイプの問題では、問題を次のように分割することをお勧めします。

  • 入力を依頼get_input入力がOKになるまで。
  • 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'

Python3.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()を使用して、入力age)のデータ型検索します。次に、次のアルゴリズムに従います。

  1. ユーザーに入力を求めますage

    1.1。ageisfloatまたは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ループとともにコードにもう1つのロジックを追加できます。

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