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
hoặc nếu bạn muốn có một thông báo "đầu vào xấu" được tách ra khỏi dấu nhắc nhập như trong các câu trả lời khác:
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
Làm thế nào nó hoạt động?
prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
Sự kết hợp này itertools.chain
và itertools.repeat
sẽ tạo ra một trình vòng lặp sẽ tạo ra chuỗi "Enter a number: "
một lần và "Not a number! Try again: "
số lần vô hạn:
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)
- ở đây map
sẽ áp dụng tất cả các prompts
chuỗi từ bước trước cho input
hàm. Ví dụ:
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...
- Chúng tôi sử dụng
filter
và str.isdigit
để lọc ra những chuỗi chỉ chứa các chữ số:
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...
Và để chỉ lấy chuỗi chữ số đầu tiên - chúng tôi sử dụng next
.
Các quy tắc xác nhận khác:
Các phương thức chuỗi: Tất nhiên bạn có thể sử dụng các phương thức chuỗi khác như str.isalpha
chỉ nhận các chuỗi chữ cái hoặc str.isupper
chỉ nhận được chữ hoa. Xem tài liệu cho danh sách đầy đủ.
Kiểm tra thành viên:
Có một số cách khác nhau để thực hiện nó. Một trong số đó là bằng __contains__
phương pháp:
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
So sánh số:
Có các phương pháp so sánh hữu ích mà chúng ta có thể sử dụng ở đây. Ví dụ: cho __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
Hoặc, nếu bạn không thích sử dụng các phương thức dunder (dunder = double-undererscore), bạn luôn có thể xác định chức năng của riêng mình hoặc sử dụng các phương thức từ operator
mô-đun.
Sự tồn tại của đường dẫn:
Ở đây người ta có thể sử dụng pathlib
thư viện và Path.exists
phương thức của nó :
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
Giới hạn số lần thử:
Nếu bạn không muốn hành hạ người dùng bằng cách hỏi anh ta một số lần vô hạn, bạn có thể chỉ định giới hạn trong một cuộc gọi itertools.repeat
. Điều này có thể được kết hợp với việc cung cấp một giá trị mặc định cho next
hàm:
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!
Tiền xử lý dữ liệu đầu vào:
Đôi khi, chúng tôi không muốn từ chối đầu vào nếu người dùng vô tình cung cấp nó trong CAPS hoặc có khoảng trắng ở đầu hoặc cuối chuỗi. Để tính đến những lỗi đơn giản này, chúng ta có thể xử lý trước dữ liệu đầu vào bằng cách áp dụng str.lower
và str.strip
phương pháp. Ví dụ, đối với trường hợp kiểm tra thành viên, mã sẽ như thế này:
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
Trong trường hợp khi bạn có nhiều hàm để sử dụng cho tiền xử lý, có thể dễ dàng hơn để sử dụng một hàm thực hiện một thành phần chức năng . Ví dụ: sử dụng một từ đây :
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
Kết hợp các quy tắc xác nhận:
Ví dụ, đối với một trường hợp đơn giản, khi chương trình yêu cầu độ tuổi từ 1 đến 120, người ta có thể chỉ cần thêm một trường hợp khác 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)
Nhưng trong trường hợp khi có nhiều quy tắc, tốt hơn là thực hiện một chức năng thực hiện kết hợp logic . Trong ví dụ sau tôi sẽ sử dụng một cái sẵn sàng từ đây :
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
Thật không may, nếu ai đó cần một thông điệp tùy chỉnh cho từng trường hợp thất bại, thì tôi sợ, không có cách nào khá hữu ích . Hoặc, ít nhất, tôi không thể tìm thấy một.