Pytanie użytkownika o wprowadzenie danych, dopóki nie poda prawidłowej odpowiedzi
Piszę program, który przyjmuje dane wejściowe od użytkownika.
#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.")
Program działa zgodnie z oczekiwaniami, o ile użytkownik wprowadzi znaczące dane.
C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!
Ale kończy się niepowodzeniem, jeśli użytkownik wprowadzi nieprawidłowe dane:
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'
Zamiast się zawieszać, chciałbym, aby program ponownie poprosił o wprowadzenie danych. Lubię to:
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!
Jak sprawić, by program poprosił o prawidłowe dane wejściowe zamiast zawieszać się, gdy wprowadzane są niesensowne dane?
Jak mogę odrzucić wartości takie jak -1
, co jest poprawne int
, ale bezsensowne w tym kontekście?
Odpowiedzi
Najprostszym sposobem osiągnięcia tego jest umieszczenie input
metody w pętli while. Użyj, continue
gdy otrzymujesz złe dane wejściowe i break
wyjdziesz z pętli, gdy jesteś zadowolony.
Kiedy Twój wkład może wywołać wyjątek
Użyj try
i,except
aby wykryć, kiedy użytkownik wprowadza dane, których nie można przeanalizować.
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.")
Wdrażanie własnych reguł walidacji
Jeśli chcesz odrzucić wartości, które Python może pomyślnie przeanalizować, możesz dodać własną logikę walidacji.
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
Połączenie obsługi wyjątków i walidacji niestandardowej
Obie powyższe techniki można połączyć w jedną pętlę.
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.")
Hermetyzowanie tego wszystkiego w funkcji
Jeśli chcesz zapytać użytkownika o wiele różnych wartości, przydatne może być umieszczenie tego kodu w funkcji, aby nie trzeba było za każdym razem go wpisywać ponownie.
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: ")
Kładąc wszystko razem
Możesz rozszerzyć ten pomysł, aby utworzyć bardzo ogólną funkcję wejściową:
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
Przy zastosowaniu takim jak:
age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))
Typowe pułapki i dlaczego należy ich unikać
Nadmiarowe użycie zbędnych input
instrukcji
Ta metoda działa, ale ogólnie jest uważana za kiepską:
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): ")
Początkowo może wyglądać atrakcyjnie, ponieważ jest krótsza niż while True
metoda, ale narusza zasadę „ Nie powtarzaj się ” w tworzeniu oprogramowania. Zwiększa to prawdopodobieństwo błędów w systemie. A co jeśli chcesz przenieść wstecz do wersji 2.7, zmieniając input
na raw_input
, ale przypadkowo zmienić tylko pierwszą z input
powyższych? To SyntaxError
tylko czekanie, aż się wydarzy.
Rekurencja rozwali Twój stos
Jeśli właśnie nauczyłeś się rekurencji, możesz ulec pokusie, aby użyć jej w programie, get_non_negative_int
aby pozbyć się pętli 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
Wydaje się, że działa to dobrze przez większość czasu, ale jeśli użytkownik wprowadzi nieprawidłowe dane wystarczająco dużo razy, skrypt zakończy działanie z rozszerzeniem RuntimeError: maximum recursion depth exceeded
. Możesz pomyśleć, że „żaden głupiec nie popełniłby 1000 błędów z rzędu”, ale nie doceniasz pomysłowości głupców!
Dlaczego miałbyś zrobić a, while True
a potem wyrwać się z tej pętli, podczas gdy możesz po prostu umieścić swoje wymagania w instrukcji while, skoro wszystko, czego chcesz, to przestać, gdy osiągniesz wiek?
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.")
Skutkowałoby to:
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.
to zadziała, ponieważ wiek nigdy nie będzie miał wartości, która nie będzie miała sensu, a kod jest zgodny z logiką Twojego „procesu biznesowego”
Chociaż przyjęta odpowiedź jest niesamowita. Chciałbym również podzielić się krótką wskazówką dotyczącą tego problemu. (To rozwiązuje również problem negatywnego wieku).
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 Ten kod jest przeznaczony dla Pythona 3.x.
Podejście funkcjonalne lub „ patrz mamo bez pętli! ”:
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
lub jeśli chcesz, aby komunikat „złe dane wejściowe” był oddzielony od monitu o wprowadzenie danych, jak w innych odpowiedziach:
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
Jak to działa?
-
Ta kombinacjaprompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
itertools.chain
iitertools.repeat
stworzy iterator, który da ciągi"Enter a number: "
raz i"Not a number! Try again: "
nieskończoną liczbę razy: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
replies = map(input, prompts)
- tutajmap
zastosuje wszystkieprompts
ciągi z poprzedniego kroku doinput
funkcji. Na przykład: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...
- Używamy
filter
i,str.isdigit
aby odfiltrować te ciągi, które zawierają tylko cyfry:only_digits = filter(str.isdigit, replies) for reply in only_digits: print(reply)
Aby otrzymać tylko pierwszy ciąg zawierający tylko cyfry, którego używamyEnter 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
.
Inne zasady walidacji:
Metody łańcuchowe: Oczywiście możesz użyć innych metod łańcuchowych, takich jak
str.isalpha
pobieranie tylko ciągów alfabetu lubstr.isupper
tylko wielkich liter. Pełną listę znajdziesz w dokumentacji .Testowanie członkostwa: można
to przeprowadzić na kilka różnych sposobów. Jednym z nich jest użycie__contains__
metody: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
Porównanie liczb:
Istnieją przydatne metody porównywania, których możemy tutaj użyć. Na przykład dla__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
Lub, jeśli nie lubisz używać metod dunder (dunder = double-underscore), zawsze możesz zdefiniować własną funkcję lub użyć tych z
operator
modułu.Istnienie ścieżki:
Tutaj można skorzystać zpathlib
biblioteki i jejPath.exists
metody: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
Ograniczenie liczby prób:
Jeśli nie chcesz torturować użytkownika, pytając go o coś nieskończoną liczbę razy, możesz określić limit w wezwaniu itertools.repeat
. Można to połączyć z podaniem domyślnej wartości next
funkcji:
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!
Wstępne przetwarzanie danych wejściowych:
Czasami nie chcemy odrzucać danych wejściowych, jeśli użytkownik przypadkowo podał je WIELKIMI LITERAMI lub spacją na początku lub na końcu łańcucha. Aby wziąć pod uwagę te proste błędy, możemy wstępnie przetworzyć dane wejściowe, stosując metody str.lower
i str.strip
metody. Na przykład w przypadku testowania członkostwa kod będzie wyglądał następująco:
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
W przypadku, gdy masz wiele funkcji do wykorzystania do przetwarzania wstępnego, łatwiejsze może być użycie funkcji wykonującej kompozycję funkcji . Na przykład używając tego stąd :
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
Łączenie reguł walidacji:
W prostym przypadku, na przykład, gdy program pyta o wiek od 1 do 120 lat, można po prostu dodać kolejny 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)
Ale w przypadku, gdy istnieje wiele reguł, lepiej zaimplementować funkcję wykonującą koniunkcję logiczną . W poniższym przykładzie użyję gotowego stąd :
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
Niestety, jeśli ktoś potrzebuje niestandardowego komunikatu dla każdej nieudanej sprawy, to obawiam się, że nie ma całkiem funkcjonalnego sposobu. A przynajmniej nie mogłem go znaleźć.
Tak więc ostatnio bawiłem się czymś podobnym do tego i wymyśliłem następujące rozwiązanie, które wykorzystuje sposób uzyskiwania danych wejściowych, które odrzucają śmieci, zanim zostaną nawet sprawdzone w logiczny sposób.
read_single_keypress()
dzięki uprzejmości 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()
Kompletny moduł można znaleźć tutaj .
Przykład:
$ ./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!
$ _
Zauważ, że natura tej implementacji polega na tym, że zamyka stdin, gdy tylko zostanie odczytana rzecz, która nie jest cyfrą. Nie nacisnąłem enter po a
, ale musiałem po liczbach.
Możesz połączyć to z thismany()
funkcją w tym samym module, aby zezwolić tylko na, powiedzmy, trzy cyfry.
Za pomocą Click :
Click to biblioteka interfejsów wiersza poleceń, która zapewnia funkcjonalność zadawania użytkownikowi prawidłowej odpowiedzi.
Prosty przykład:
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
Zwróć uwagę, jak automatycznie przekonwertował wartość ciągu na liczbę zmiennoprzecinkową.
Sprawdzanie, czy wartość mieści się w zakresie:
Dostępne są różne typy niestandardowe . Aby uzyskać liczbę z określonego zakresu, możemy użyć 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
Możemy też określić tylko jedno z ograniczeń min
lub 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
Testowanie członkostwa:
Używanie click.Choice
typu. Domyślnie to sprawdzenie rozróżnia wielkość liter.
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
Praca ze ścieżkami i plikami:
Używając click.Path
typu, możemy sprawdzić istniejące ścieżki, a także je rozwiązać:
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
Czytanie i zapisywanie plików można wykonać przez 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!
Inne przykłady:
Potwierdzenie hasła:
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
Wartości domyślne:
W takim przypadku po prostu naciśnięcie Enter(lub dowolnego klawisza, którego używasz) bez wprowadzania wartości, da ci domyślną:
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
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."
Opierając się na doskonałych sugestiach Daniela Q i Patricka Artnera, oto jeszcze bardziej ogólne rozwiązanie.
# 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)
Zdecydowałem się na jawne if
i raise
instrukcje zamiast a assert
, ponieważ sprawdzanie asercji może być wyłączone, podczas gdy walidacja powinna być zawsze włączona, aby zapewnić niezawodność.
Można to wykorzystać do uzyskania różnych rodzajów danych wejściowych, z różnymi warunkami walidacji. Na przykład:
# 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!"})
Lub, aby odpowiedzieć na pierwotne pytanie:
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.")
Spróbuj tego:-
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')
Tak, spóźniłem się 6 lat od 🎉, ale to pytanie zasługuje na bardziej aktualną odpowiedź.
Rozdzielenie obaw
Jestem wielkim fanem filozofii Uniksa „Zrób jedną rzecz i zrób to dobrze” . W tego typu problemach lepiej jest podzielić problem
- Pytaj,
get_input
aż wejście będzie w porządku. - Sprawdź poprawność w
validator
funkcji. Możesz napisać różne walidatory dla różnych zapytań wejściowych.
Prośba o wkład
Może być tak prosty, jak (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)
Przykład
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+ Uwaga
W Pythonie 3.8+ możesz użyć operatora morsa
def get_input(prompt, validator, on_validationerror):
while not validator(value := input(prompt)):
print(on_validationerror)
return value
Chociaż try
/ except
blok będzie działał, znacznie szybszym i czystszym sposobem wykonania tego zadania byłoby użycie 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.")
Dobre pytanie! W tym celu możesz wypróbować następujący kod. =)
Ten kod używa ast.literal_eval () do znalezienia typu danych input ( age
). Następnie postępuje zgodnie z następującym algorytmem:
Poproś użytkownika o wprowadzenie jej
age
.1.1. Jeśli
age
jestfloat
lubint
typ danych:
Sprawdź, czy
age>=18
. Jeśliage>=18
, wydrukuj odpowiednie wyjście i zakończ.Sprawdź, czy
0<age<18
. Jeśli0<age<18
, wydrukuj odpowiednie wyjście i zakończ.Jeśli
age<=0
poproś użytkownika o ponowne wprowadzenie prawidłowej liczby określającej wiek ( tj. Wróć do kroku 1.)1.2. Jeśli
age
niefloat
lubint
typ danych, poproś użytkownika o ponowne wprowadzenie wieku ( tj. Wróć do kroku 1).
Oto kod.
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.")
Zawsze możesz zastosować prostą logikę if-else i dodać jeszcze jedną if
logikę do kodu wraz z for
pętlą.
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
To będzie nieskończona toaleta i zostaniesz poproszony o wejście w ten wiek na czas nieokreślony.
Poniższy kod może pomóc.
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='')
Jeśli chcesz mieć maksymalną liczbę prób, powiedzmy 3, użyj poniższego kodu
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='')
Uwaga: używa rekurencji.
Użyj try-except, aby obsłużyć błąd i powtórz go ponownie:
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")