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
atau jika Anda ingin memisahkan pesan "input buruk" dari prompt input seperti pada jawaban lain:
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
Bagaimana cara kerjanya?
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
Kombinasi dari itertools.chain
dan itertools.repeat
akan menciptakan iterator yang akan menghasilkan string "Enter a number: "
sekali, dan "Not a number! Try again: "
dalam jumlah tak terbatas:
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)
- di sini map
akan menerapkan semua prompts
string dari langkah sebelumnya ke input
fungsi. Misalnya:
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...
- Kami menggunakan
filter
dan str.isdigit
memfilter string yang hanya berisi digit:
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...
Dan untuk mendapatkan hanya string digit-only pertama yang kami gunakan next
.
Aturan validasi lainnya:
Metode string: Tentu saja Anda dapat menggunakan metode string lain seperti str.isalpha
hanya mendapatkan string alfabet, atau str.isupper
hanya mendapatkan huruf besar. Lihat dokumen untuk daftar lengkap.
Pengujian keanggotaan:
Ada beberapa cara berbeda untuk melakukannya. Salah satunya dengan menggunakan __contains__
metode:
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
Perbandingan angka:
Ada metode perbandingan berguna yang bisa kita gunakan di sini. Misalnya, untuk __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
Atau, jika Anda tidak suka menggunakan metode dunder (dunder = double-underscore), Anda selalu dapat mendefinisikan fungsi Anda sendiri, atau menggunakan yang dari operator
modul.
Jalur keberadaan:
Di sini orang dapat menggunakan pathlib
perpustakaan dan Path.exists
metodenya:
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
Membatasi jumlah percobaan:
Jika Anda tidak ingin menyiksa pengguna dengan menanyakan sesuatu sesuatu dalam jumlah tak terbatas, Anda dapat menentukan batas dalam panggilan itertools.repeat
. Ini dapat dikombinasikan dengan memberikan nilai default ke next
fungsi:
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!
Input data preprocessing:
Terkadang kami tidak ingin menolak input jika pengguna secara tidak sengaja memasukkannya dalam CAPS atau dengan spasi di awal atau akhir dari string. Untuk memperhitungkan kesalahan sederhana ini, kita dapat memproses ulang input data dengan menerapkan str.lower
dan str.strip
metode. Misalnya, untuk kasus pengujian keanggotaan, kode akan terlihat seperti ini:
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
Dalam kasus ketika Anda memiliki banyak fungsi untuk digunakan untuk preprocessing, mungkin lebih mudah untuk menggunakan fungsi yang melakukan komposisi fungsi . Misalnya, menggunakan yang dari sini :
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
Menggabungkan aturan validasi:
Untuk kasus sederhana, misalnya, ketika program meminta usia antara 1 dan 120, orang bisa menambahkan yang lain 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)
Tetapi dalam kasus ketika ada banyak aturan, lebih baik untuk mengimplementasikan fungsi yang melakukan konjungsi logis . Dalam contoh berikut ini saya akan menggunakan yang siap dari sini :
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
Sayangnya, jika seseorang membutuhkan pesan khusus untuk setiap kasus yang gagal, maka, saya khawatir, tidak ada yang cantik cara yang fungsional. Atau, setidaknya, saya tidak dapat menemukannya.