Najprostszym sposobem na osiągnięcie tego jest umieszczenie input
metody w pętli while. Użyj, continue
gdy dostaniesz złe dane wejściowe, i break
wyjdź z pętli, gdy będziesz zadowolony.
Kiedy Twoje dane wejściowe mogą 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 zasad walidacji
Jeśli chcesz odrzucić wartości, które Python może z powodzeniem parsować, możesz dodać własną logikę sprawdzania poprawności.
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
Łącząc obsługę wyjątków i niestandardową weryfikację
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 wszystkiego w funkcji
Jeśli musisz poprosić użytkownika o wiele różnych wartości, przydatne może być wstawienie tego kodu do funkcji, abyś nie musiał go ponownie wpisywać za każdym razem.
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 stworzyć bardzo ogólną funkcję wprowadzania:
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 jest ogólnie uważana za kiepski styl:
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ótszy niż while True
metoda, ale narusza zasadę tworzenia oprogramowania „ Nie powtarzaj się ”. Zwiększa to prawdopodobieństwo błędów w twoim systemie. Co jeśli chcesz cofnąć się do wersji 2.7, zmieniając input
na raw_input
, ale przypadkowo zmień tylko pierwszą z input
powyższych? To jestSyntaxError
tylko czekanie na wydarzenie.
Rekurencja rozwali Twój stos
Jeśli właśnie dowiedziałeś się o rekurencji, możesz mieć pokusę, aby użyć jej w get_non_negative_int
celu pozbycia 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 się za pomocą RuntimeError: maximum recursion depth exceeded
. Możesz myś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!
input
na pętlę i pętla stanie się bardzo krótka, ale stan może stać się dość długi ...Dlaczego miałbyś zrobić
while True
a następnie zerwać z tej pętli, podczas gdy możesz po prostu umieścić swoje wymagania w instrukcji while, ponieważ wszystko, czego chcesz, to przestać, gdy osiągniesz wiek?Spowodowałoby to:
zadziała to, ponieważ wiek nigdy nie będzie miał wartości, która nie będzie miała sensu, a kod będzie zgodny z logiką „procesu biznesowego”
źródło
Chociaż przyjęta odpowiedź jest niesamowita. Chciałbym również udostępnić szybki hack dla tego problemu. (To rozwiązuje również problem negatywnego wieku).
PS Ten kod dotyczy Pythona 3.x.
źródło
def
zamiast tego.def f(age):
jest znacznie jaśniejszy niżf = lambda age:
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, w jaki otrzymujesz dane wejściowe, które odrzucają śmieci, zanim zostaną nawet sprawdzone w jakikolwiek logiczny sposób.
read_single_keypress()
dzięki uprzejmości https://stackoverflow.com/a/6599441/4532996Kompletny moduł można znaleźć tutaj .
Przykład:
Zauważ, że naturą tej implementacji jest to, że zamyka ona standardowe wejście, gdy tylko zostanie przeczytane coś, co nie jest cyfrą. Później nie nacisnąłem Enter
a
, ale musiałem po liczbach.Można to połączyć z
thismany()
funkcją w tym samym module, aby pozwolić, powiedzmy, na trzy cyfry.źródło
Funkcjonalne podejście lub „ look mama bez pętli! ”:
lub jeśli chcesz, aby komunikat „niepoprawne dane wejściowe” był oddzielony od monitu o wprowadzenie, jak w innych odpowiedziach:
Jak to działa?
itertools.chain
iitertools.repeat
utworzy iterator, który da ciągi"Enter a number: "
raz i"Not a number! Try again: "
nieskończoną liczbę razy:replies = map(input, prompts)
- tutajmap
zastosuje wszystkieprompts
ciągi z poprzedniego kroku doinput
funkcji. Na przykład:filter
istr.isdigit
do filtrowania ciągów zawierających tylko cyfry: I aby uzyskać tylko pierwsze ciągi zawierające tylko cyfry, których używamynext
.Inne zasady sprawdzania poprawności:
Metody ciągów: Oczywiście możesz użyć innych metod ciągów, takich jak
str.isalpha
uzyskiwanie tylko ciągów alfabetycznych lubstr.isupper
tylko wielkich liter. Widzieć docs dla pełnej listy.Testowanie członkostwa:
Istnieje kilka różnych sposobów jego wykonania. Jednym z nich jest użycie
__contains__
metody:Porównanie liczb:
istnieją przydatne metody porównywania, których możemy użyć tutaj. Na przykład dla
__lt__
(<
):Lub, jeśli nie lubisz używać metod dundera (dunder = double-undercore), zawsze możesz zdefiniować własną funkcję lub użyć funkcji z
operator
modułu.Istnienie ścieżki:
Tutaj można użyć
pathlib
biblioteki i jejPath.exists
metody:Ograniczająca liczba prób:
Jeśli nie chcesz torturować użytkownika, zadając mu nieskończoną liczbę pytań, możesz określić limit w wywołaniu
itertools.repeat
. Można to połączyć z dostarczeniem wartości domyślnej dlanext
funkcji:Wstępne przetwarzanie danych wejściowych:
Czasami nie chcemy odrzucać danych wejściowych, jeśli użytkownik przypadkowo dostarczył je W CAPSACH lub ze 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
str.lower
istr.strip
metody. Na przykład w przypadku testowania członkostwa kod będzie wyglądał następująco:W przypadku, gdy masz wiele funkcji do wstępnego przetwarzania, łatwiejsze może być użycie funkcji wykonującej kompozycję funkcji . Na przykład, korzystając z tego tutaj :
Łączenie reguł sprawdzania poprawności:
W prostym przypadku, na przykład, gdy program prosi o wiek od 1 do 120 lat, można po prostu dodać inny
filter
:Ale w przypadku, gdy istnieje wiele reguł, lepiej zaimplementować funkcję wykonującą logiczną koniunkcję . W poniższym przykładzie użyję gotowego stąd :
Niestety, jeśli ktoś potrzebuje niestandardowego komunikatu dla każdej nieudanej sprawy, obawiam się, że nie ma całkiem funkcjonalnego sposobu. A przynajmniej nie mogłem znaleźć.
źródło
Za pomocą Click :
Click jest biblioteką dla interfejsów wiersza poleceń i zapewnia funkcjonalność umożliwiającą uzyskanie prawidłowej odpowiedzi od użytkownika.
Prosty przykład:
Zauważ, 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
:Możemy również określić tylko jeden z limitów
min
lubmax
:Testowanie członkostwa:
Używanie
click.Choice
typu. Domyślnie w tym sprawdzeniu rozróżniana jest wielkość liter.Praca ze ścieżkami i plikami:
Za pomocą
click.Path
typu możemy sprawdzić istniejące ścieżki, a także je rozwiązać:Odczytywanie i zapisywanie plików można wykonać poprzez
click.File
:Inne przykłady:
Potwierdzenie hasła:
Wartości domyślne:
W takim przypadku wystarczy nacisnąć Enter(lub jakikolwiek używany klawisz) bez wprowadzania wartości, aby uzyskać domyślny:
źródło
źródło
Opierając się na doskonałych sugestiach Daniela Q i Patricka Artnera, oto jeszcze bardziej ogólne rozwiązanie.
Zdecydowałem się na wyraźne
if
iraise
oświadczenia zamiastassert
, ponieważ sprawdzanie asercji może być wyłączone, podczas gdy sprawdzanie poprawności powinno być zawsze włączone, aby zapewnić niezawodność.Może to być wykorzystane do uzyskania różnych rodzajów danych wejściowych, z różnymi warunkami walidacji. Na przykład:
Lub, aby odpowiedzieć na oryginalne pytanie:
źródło
Spróbuj tego:-
źródło
Podczas gdy blok
try
/except
będzie działał, znacznie szybszym i czystszym sposobem na wykonanie tego zadania byłoby użyciestr.isdigit()
.źródło
Dobre pytanie! Możesz wypróbować następujący kod. =)
Ten kod używa ast.literal_eval (), aby znaleźć typ danych input (
age
). Następnie postępuje według następującego algorytmu:Oto kod.
źródło
Zawsze możesz zastosować prostą logikę if-else i dodać jeszcze jedną
if
logikę do swojego kodu wraz zfor
pętlą.To będzie nieskończony kibel i zostaniesz poproszony o wejście w wiek na czas nieokreślony.
źródło
Możesz napisać bardziej ogólną logikę, aby umożliwić użytkownikowi wprowadzanie tylko określonej liczby razy, ponieważ taki sam przypadek użycia występuje w wielu rzeczywistych aplikacjach.
źródło
Możesz wykonać instrukcję wejściową na chwilę True, aby wielokrotnie pytała o dane wejściowe użytkowników, a następnie przerwać tę pętlę, jeśli użytkownik wprowadzi odpowiedź, którą chcesz. I możesz użyć try i oprócz bloków do obsługi nieprawidłowych odpowiedzi.
Zmienna var jest taka, że jeśli użytkownik wprowadzi ciąg zamiast liczby całkowitej, program nie zwróci „Nie można głosować w Stanach Zjednoczonych”.
źródło
Używaj instrukcji „while”, dopóki użytkownik nie wprowadzi prawdziwej wartości, a jeśli wartość wejściowa nie jest liczbą lub jest wartością zerową, pomiń ją i spróbuj ponownie zapytać i tak dalej. Na przykład próbowałem odpowiedzieć naprawdę na twoje pytanie. Jeśli przypuszczamy, że nasz wiek wynosi od 1 do 150, wówczas wartość wejściowa jest akceptowana, w przeciwnym razie jest to zła wartość. Do zakończenia programu użytkownik może użyć klawisza 0 i wprowadzić go jako wartość.
źródło
Jeszcze jedno rozwiązanie do używania sprawdzania poprawności danych wejściowych przy użyciu niestandardowego
ValidationError
i (opcjonalnego) sprawdzania poprawności zakresu dla liczb całkowitych:Stosowanie:
Wynik:
źródło
Oto czystsze, bardziej uogólnione rozwiązanie, które pozwala uniknąć powtarzających się bloków if / else: napisz funkcję, która bierze pary (Błąd, monit o błąd) w słowniku i wykonuj wszystkie sprawdzenia wartości za pomocą asercji.
Stosowanie:
źródło
Stałe wprowadzanie danych przez użytkownika za pomocą funkcji rekurencyjnej :
Strunowy
Liczba całkowita
i wreszcie wymóg pytania:
źródło
Prostym rozwiązaniem byłoby:
Wyjaśnienie powyższego kodu: Aby uzyskać prawidłowy wiek, powinien być dodatni i nie powinien być dłuższy niż normalny wiek fizyczny, np. Maksymalny wiek to 120 lat.
Następnie możemy poprosić użytkownika o podanie wieku, a jeśli wartość wieku jest ujemna lub wyższa niż 120, uważamy, że jest to nieprawidłowa wartość i prosi użytkownika o ponowną próbę.
Po wprowadzeniu prawidłowych danych wejściowych sprawdzamy (za pomocą zagnieżdżonej instrukcji if-else), czy wiek wynosi> = 18 lub odwrotnie, i drukujemy komunikat, czy użytkownik jest uprawniony do głosowania
źródło
weź dane wejściowe jako ciąg i użyj isdigit (), aby sprawdzić, czy dane wejściowe mają tylko cyfry, a nie puste, nie mogę być
źródło