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
oder wenn Sie möchten, dass eine "schlechte Eingabe" von einer Eingabeaufforderung wie in anderen Antworten getrennt wird:
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
Wie funktioniert es?
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
Diese Kombination von itertools.chain
und itertools.repeat
erzeugt einen Iterator, der "Enter a number: "
einmal und "Not a number! Try again: "
unendlich oft Zeichenfolgen liefert :
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)
- Hier map
werden alle prompts
Zeichenfolgen aus dem vorherigen Schritt auf die input
Funktion angewendet. Z.B:
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...
- Wir verwenden
filter
und str.isdigit
filtern die Zeichenfolgen heraus, die nur Ziffern enthalten:
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...
Und um nur die erste Nur-Ziffern-Zeichenfolge zu erhalten, die wir verwenden next
.
Andere Validierungsregeln:
String-Methoden: Natürlich können Sie auch andere String-Methoden verwenden str.isalpha
, um nur alphabetische Strings oder str.isupper
nur Großbuchstaben zu erhalten. Die vollständige Liste finden Sie in den Dokumenten .
Mitgliedschaftstests:
Es gibt verschiedene Möglichkeiten, dies durchzuführen. Eine davon ist die Verwendung der folgenden __contains__
Methode:
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
Zahlenvergleich:
Es gibt nützliche Vergleichsmethoden, die wir hier verwenden können. Zum Beispiel für __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
Wenn Sie keine Dunder-Methoden verwenden möchten (Dunder = doppelter Unterstrich), können Sie jederzeit Ihre eigene Funktion definieren oder die aus dem operator
Modul verwenden.
Pfadexistenz:
Hier kann man die pathlib
Bibliothek und ihre Path.exists
Methode verwenden:
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
Begrenzung der Anzahl der Versuche:
Wenn Sie einen Benutzer nicht foltern möchten, indem Sie ihn unendlich oft nach etwas fragen, können Sie in einem Anruf von ein Limit angeben itertools.repeat
. Dies kann mit der Bereitstellung eines Standardwerts für die next
Funktion kombiniert werden:
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!
Eingabedaten vorverarbeiten:
Manchmal möchten wir eine Eingabe nicht ablehnen, wenn der Benutzer sie versehentlich IN GROSSBUCHSTABEN oder mit einem Leerzeichen am Anfang oder Ende der Zeichenfolge angegeben hat. Um diese einfachen Fehler zu berücksichtigen, können wir die Eingabedaten durch Anwenden str.lower
und str.strip
Methoden vorverarbeiten . Für den Fall des Mitgliedschaftstests sieht der Code beispielsweise folgendermaßen aus:
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
Im Fall , wenn Sie viele Funktionen nutzen für die Vorverarbeitung haben, könnte es einfacher sein , eine Funktion zu verwenden , um eine Durchführung Funktion Zusammensetzung . Verwenden Sie zum Beispiel die von hier :
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
Validierungsregeln kombinieren:
In einem einfachen Fall, wenn das Programm beispielsweise nach einem Alter zwischen 1 und 120 Jahren fragt, kann man einfach ein weiteres hinzufügen 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)
Wenn es jedoch viele Regeln gibt, ist es besser, eine Funktion zu implementieren, die eine logische Konjunktion ausführt . Im folgenden Beispiel werde ich von hier aus ein fertiges verwenden :
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
Wenn jemand für jeden fehlgeschlagenen Fall eine benutzerdefinierte Nachricht benötigt, gibt es leider keinen ziemlich funktionalen Weg. Zumindest konnte ich keinen finden.