유효한 응답을 제공 할 때까지 사용자에게 입력 요청


562

사용자의 입력을 수락하는 프로그램을 작성 중입니다.

#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하지만 무의미한 값을 어떻게 거부 할 수 있습니까?

답변:


704

이 작업을 수행하는 가장 간단한 방법은 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방법 보다 짧기 때문에 처음에는 매력적으로 보일지 모르지만 소프트웨어 개발의 자체 반복 원칙을 위반합니다 . 이것은 시스템의 버그 가능성을 높입니다. 로 변경 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 번 실수하지 않을 것"이라고 생각할 수도 있지만, 바보의 독창성을 과소 평가하고 있습니다!


53
많은 예제, kudos로 읽는 것이 재미 있습니다. 과소 평가 : "바보의 독창성을 과소 평가하지 마십시오!"
vpibano

3
어쨌든 둘 다 Q & A를 찬성했을뿐만 아니라 "6 번"과의 거래를 성사시켰다. 잘 했어, @Kevin.
erekalper

1
바보와 영리한 공격자의 독창성을 추정하지 마십시오. DOS 공격은 이런 종류의 일에 가장 쉬운 방법이지만 다른 방법도 가능합니다.
Solomon Ucko

중복 입력 대신 새로운 "해마"연산자를 사용할 수 있습니까? 스타일도 좋지 않습니까?
J Arun Mani

1
@JArunMani 나는 스타일이 좋지 않다고 생각하지만 읽기 쉽지는 않습니다. 당신은 실제로 input루프 당 하나만 가질 것이고 루프는 매우 짧아 질 것이지만, 상태는 꽤 길어질 것입니다 ...
Tomerikoo

39

왜 당신은 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.

이것은 나이가 의미가없는 가치를 가지지 않기 때문에 작동하며 코드는 "비즈니스 프로세스"의 논리를 따릅니다.


22

받아 들여진 대답은 훌륭합니다. 또한이 문제에 대한 빠른 해킹을 공유하고 싶습니다. (이것은 부정적인 연령 문제도 처리합니다.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

PS이 코드는 python 3.x 용입니다.


1
이 코드는 재귀 적이지만 재귀는 필요하지 않으며 Kevin이 말했듯이 스택을 날려 버릴 수 있습니다.
PM 2Ring

2
@ PM2Ring-맞습니다. 그러나 여기서의 목적은 "단락"이 긴 코드를 최소화 (미화) 할 수있는 방법을 보여주기위한 것입니다.
aaveg

11
변수에 람다를 할당하는 이유는 def대신 사용하십시오. def f(age):f = lambda age:
GP89

3
경우에 따라 한 번만 나이가 필요할 수 있으며 해당 기능을 사용하지 않습니다. 함수를 사용하고 작업이 끝나면 버릴 수도 있습니다. 또한 이것이 최선의 방법은 아니지만 분명히 다른 방법입니다 (내 솔루션의 목적이었습니다).
aaveg

@aaveg 사용자가 제공 한 연령을 실제로 절약하기 위해이 코드를 어떻게 설정 하시겠습니까?
Tytire Recubans 님이

12

그래서 최근에 이와 비슷한 것을 엉망으로 만들었고 논리적으로 검사하기 전에 정크를 거부하는 입력을 얻는 방법을 사용하는 다음 솔루션을 생각해 냈습니다.

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()같은 모듈 의 함수 와 병합하여 세 자리 만 허용 할 수 있습니다.


12

기능적 접근 방식 또는 " 루프가없는 것처럼 보입니다! ":

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: "한 번, 그리고 "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 = 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!

전처리 입력 데이터 :

때때로 우리는 사용자가 실수로 공급하는 경우 입력을 거부하지 않으려는 대문자 또는 처음에 공백이나 문자열의 끝. 이러한 간단한 실수를 고려하기 위해 str.lowerand 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

누군가가 각 실패한 경우에 사용자 정의 메시지를 필요로하는 경우 불행하게도, 다음, 난 두려워, 어떤이없는 매우 기능적인 방법입니다. 또는 적어도 하나를 찾을 수 없습니다.


얼마나 철저하고 훌륭한 답변입니까? 설명 분석은 훌륭했습니다.
Locane September

스타일을 사용하여 멤버쉽 테스트를 위해 공백을 제거하고 입력을 줄이려면 어떻게해야합니까? 대문자와 소문자 예제를 모두 포함 해야하는 세트를 만들고 싶지 않습니다. 또한 공백 입력 실수를 허용하고 싶습니다.
Austin

1
@Austin 전처리에 대한 새로운 섹션을 추가했습니다. 구경하다.
Georgy

ReactiveX를 생각 나게합니다. 그러나 아마도 그것은 처음부터 기능적 언어에서 영감을 얻은 것일까 요?
Mateen Ulhaq

8

클릭 사용 :

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

Daniel Q와 Patrick Artner의 훌륭한 제안을 바탕으로보다 일반적인 솔루션이 있습니다.

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

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

어설 션 검사가 해제 될 수있는 반면에 견고성을 제공하기 위해 유효성 검사는 항상 켜져 있어야하므로, 대신 명시 적 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

이거 한번 해봐:-

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

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

0

좋은 질문! 이를 위해 다음 코드를 시도 할 수 있습니다. =)

이 코드는 ast.literal_eval () 을 사용 하여 입력 ( 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.") 

0

간단한 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

이것은 무한 화장실이 될 것이며, 당신은 무기한으로 나이를 입력하도록 요청받을 것입니다.


이것은 실제로 질문에 대답하지 않습니다. 질문은 무기한이 아닌 유효한 응답을 줄 때까지 사용자 입력을 얻는 것에 관한 입니다.
Georgy

-1

많은 실제 응용 프로그램에서 동일한 사용 사례가 발생하므로 사용자가 특정 횟수 만 입력 할 수 있도록보다 일반적인 논리를 작성할 수 있습니다.

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
당신은 각 루프 후에 iCount 값을 증가시키는 것을 잊었다
Hoai-Thu Vuong

-1

input 문을 while True 루프로 만들면 반복해서 사용자 입력을 요청한 다음 사용자가 원하는 응답을 입력하면 해당 루프를 끊을 수 있습니다. try 및 except 블록을 사용하여 유효하지 않은 응답을 처리 할 수 ​​있습니다.

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

var 변수는 사용자가 정수 대신 문자열을 입력하면 프로그램이 "미국에서 투표 할 수 없음"을 반환하지 않도록하기위한 것입니다.


-1

사용자가 실제 값을 입력 할 때까지 "while"문을 사용하고 입력 값이 숫자가 아니거나 널값 인 경우이를 건너 뛰고 다시 요청하십시오. 예를 들어 나는 당신의 질문에 진정으로 답하려고 노력했습니다. 나이가 1에서 150 사이라고 가정하면 입력 값이 허용됩니다. 그렇지 않으면 잘못된 값입니다. 프로그램 종료의 경우 사용자는 0 키를 사용하여 값으로 입력 할 수 있습니다.

참고 : 코드 상단의 주석을 읽으십시오.

# 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

ValidationError정수 입력에 대해 사용자 지정 및 (선택적) 범위 유효성 검사를 사용하여 입력 유효성 검사를 사용하기위한 또 하나의 솔루션 :

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

용법:

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)

산출:

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

다음은 반복적 인 if / else 블록을 피하는 더 깨끗하고 더 일반적인 솔루션입니다. 사전에서 (오류, 오류 프롬프트) 쌍을 취하는 함수를 작성하고 어설 션으로 모든 값 확인을 수행하십시오.

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

용법:

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

-1

재귀 기능을 사용한 지속적인 사용자 입력 :

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

name = askName()

정수

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

age = askAge()

마지막으로 질문 요구 사항 :

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

간단한 해결책은 다음과 같습니다.

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

위 코드에 대한 설명 : 유효한 연령을 유지하려면 양수 여야하며 정상적인 신체 연령을 초과해서는 안됩니다 (예 : 최대 연령은 120입니다).

그런 다음 사용자에게 연령을 물어볼 수 있고 연령 입력이 음수이거나 120보다 큰 경우 잘못된 입력으로 간주하고 사용자에게 다시 시도하도록 요청합니다.

유효한 입력이 입력되면 연령이 18보다 크거나 그 반대인지 여부를 확인 (중첩 된 if-else 문 사용)하고 사용자가 투표 할 수 있는지 여부를 메시지로 인쇄합니다


"나이를 입력하십시오 : dickety six" ': 질문에 명시된 것과 같은 충돌 ...
BDL

-2

입력을 문자열로 사용하고 isdigit ()를 사용하여 입력에 비어 있지 않은 숫자 만 있는지 확인하십시오.

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


또한 질문에 대답하지 않습니다.
조지
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.